Debugging memory leaks - HTTP 203

Debugging memory leaks - HTTP 203


Debugging memory leaks - HTTP 203

Jake and Surma tackle one of the hardest types of debugging on the web: Memory leaks.

Some links mentioned:
Squoosh → https://goo.gle/2OQBnGG
Leaky version of Squoosh, so you can try the tools for yourself → https://goo.gle/3A7Lwni
Original bug report → https://goo.gle/3jhl7wj

Resize/Intersection observer bug reports:
Chrome → https://goo.gle/3rOXM9l
Firefox → https://goo.gle/3s3u54B
Safari → https://goo.gle/3xlerT8

More videos in the HTTP 203 series → http://goo.gle/HTTP203
Subscribe to Google Chrome Developers here → https://goo.gle/ChromeDevs

Also, if you enjoyed this, you might like the HTTP203 podcast → https://goo.gle/HTTP203Podcast

#HTTP203 #ChromeDeveloper #WebDev


Content

0.48 -> already take two
2.08 -> what happened to the one take wonders i
4.08 -> know i know we were doing quite well at
5.839 -> home weren't we
7.279 -> this is a second take
8.28 -> [Music]
15.12 -> we're back well yeah we are
18.24 -> in our new basement studio temporary
20.16 -> accommodation but better than
22.64 -> none i'd say yeah absolutely yeah and um
26.16 -> i thought
27.359 -> you know i'm gonna throw us into the
29.199 -> deep end
30.4 -> oh there's no easing in
32.16 -> coming back from the working from home
34.399 -> filming from home era even straight okay
37.68 -> straight in
38.719 -> to debugging memory leaks
41.12 -> everyone's favorite i i think it's the
43.04 -> hardest thing to do with devtools well
44.64 -> how does that agree yeah just in general
46.879 -> trying to do something like
48.96 -> trying to figure out where where memory
50.239 -> is going it's so much harder than you
52.559 -> know figuring out css problems so much
54.079 -> harder than figuring out performance
55.12 -> problems it's it's already hard i think
56.96 -> in garbage collected languages in
58.8 -> general to figure out when is something
61.199 -> being garbage collected and reason about
62.96 -> that and now put on top that our
65.68 -> we have tools and devtools
68.799 -> but they just
70.24 -> give you numbers and then go you figure
72.24 -> it out and we're going to look at some
73.92 -> of those numbers great i've figured out
75.76 -> what some of them mean not all of them
77.04 -> but some of them so what happened is uh
79.52 -> someone on github
80.96 -> let us know that um squoosh
84.08 -> i know this app yeah it's the thing we
86.4 -> built
87.28 -> uh that we still wanted a couple more
88.799 -> but yeah
89.84 -> you know this is the one we still
90.96 -> maintain
92.24 -> so yeah but they were saying it's using
94 -> a lot of memory
95.2 -> i mean and that's images it does images
97.52 -> and they're big so that's that was the
98.72 -> first thing i said it's like yeah i mean
100.479 -> it's gonna and like no no no it's using
102.799 -> more and more memory uh
105.6 -> that's not good classic memory leak
107.6 -> territory yeah so the first thing i want
109.759 -> to do is like you know can i recreate
111.28 -> this problem so i went into uh dev tools
114.399 -> and into the old memory tab
117.04 -> uh how did they figure it out
119.2 -> uh they saw it in task manager
121.6 -> they saw the memory going up and up and
123.04 -> up which you can use as well but then it
125.119 -> sort of mixes in
126.56 -> like other processes it's harder to see
128.72 -> i could imagine it's the kind of thing
129.84 -> where chrome sometimes grabs memory and
132.4 -> even though the process that the
134 -> renderer process health frees it back up
136 -> chrome doesn't give it back because it
138.319 -> might need it or something yep that's
140.8 -> classically chrome behavior
142.48 -> i might need all of your memory so i'll
144.239 -> take it now
145.44 -> um but yeah this is how i recreate it
147.2 -> and
147.92 -> we got a comment a couple of episodes
150.319 -> ago where someone was saying look i
151.599 -> watch your episodes on my mobile and i
154 -> struggle to read some of the code can
155.28 -> you make the code bigger
157.12 -> sorry mate you're not going to like this
159.04 -> one because the the tools are dense
161.36 -> they're really really i think they're
163.28 -> mostly glorified
165.12 -> spreadsheets lots of numbers and so you
167.04 -> either get big numbers but only see a
168.879 -> third of the data is available
171.28 -> how do you make them smaller yeah i've
172.959 -> zoomed in as much as i can look i'll
174.16 -> zoom in a little bit more that's as much
176.319 -> as we can do
178.08 -> but you'll see in these videos i'm
179.76 -> struggling even with some of the column
181.2 -> sizes because i've zoomed it maybe
182.959 -> slightly too much anyway
184.4 -> let's let's see how easy this is to
186.64 -> understand the first thing i did is take
188.4 -> a heap snapshot when you press that
190.319 -> button what it does is it does uh an
192.56 -> aggressive piece of garbage collection
195.04 -> and then goes right finds everything
197.68 -> that javascript has
199.76 -> caused or so basically make sure that
201.84 -> everything that can be deleted is
204.08 -> deleted and then it measures how much
206.4 -> you have on your heap because that's the
208.159 -> part where javascript
210.48 -> objects slip well you'll see that this
212.239 -> there's a few icons there's a bin icon
214.159 -> and there's a no icon
216 -> and the bin icon
218.64 -> what does that do
219.84 -> that runs garbage collection it does yes
221.519 -> well done whereas the no icon deletes
223.36 -> things like you know
224.64 -> the actual snapshots yeah traditionally
226.4 -> the bin for throwing stuff away that's
228.4 -> not what's happening here it's just for
229.519 -> garbage collection but you don't
230.4 -> actually need to press that it's done
231.599 -> automatically okay now i know an array
234 -> has a shallow size of 590 000 which is
237.36 -> 22 percent that is very insightful yes
240.48 -> and so it's like we're using two
241.84 -> megabytes or 2.7 megabytes not very
244.08 -> interesting but now i've opened an image
246.239 -> i've taken another heap snapshot we're
247.519 -> up to 80
248.64 -> megabytes that makes sense for that
250.4 -> image i'd say like it's a do you
252.159 -> remember the the resolution yeah like 3
255.04 -> 000 by something three it's a big image
258.079 -> three by two so it's like six million
260.16 -> pixels so 24 million bytes
265.199 -> yeah i i thought are you going to see
266.639 -> this maps through you're going to do
268.08 -> yeah
268.88 -> sounds about right sounds about right
270.16 -> excellent cool
271.44 -> um and that's yeah it sounded about
273.36 -> right to me like just memory going up
274.88 -> isn't a problem we've loaded a big image
277.04 -> and now we have a big images worth of
279.919 -> memory being used and we actually see
282.4 -> this
283.28 -> on the side there
284.56 -> what i can do is do this comparison and
286.479 -> say hey show me the difference between
288 -> snapshot one and snapshot two and we can
290.16 -> see here there's these three array
291.84 -> buffers 40 megabytes each well there's
294.32 -> two of them are 40 megabytes and one of
295.68 -> them is significantly less
298 -> how
298.88 -> how did you know to look there because
300.479 -> there's also many other things you could
301.919 -> have unfolded it was the biggest things
305.28 -> there
306 -> which is usually the first thing to do
307.12 -> is there anything like it's memory's
308.479 -> gone up a lot but is there anything big
311.28 -> this stuff gets a lot harder if it's
313.28 -> lots of little things
314.88 -> thankfully for this one as memory
316.56 -> debugging goes it was pretty easy
318.56 -> because it's three big things so there's
320.24 -> two gs arrays that are exactly the same
321.84 -> size i'm assuming that is the copy of
323.919 -> the image on the main thread and the
325.28 -> other one from the worker because we're
326.72 -> probably going to have two copies of the
328.4 -> image flying around so you
330.72 -> you raised an interesting point here is
332.32 -> like i think if
334.24 -> if i'm looking at performance i can just
336.88 -> go to a random website and i can look at
339.28 -> the the performance timeline and i can
340.96 -> come up with some
342.479 -> decent recommendation
344.16 -> i would say when you're debugging memory
345.68 -> stuff
346.72 -> you really need some knowledge of the
348.24 -> app
349.28 -> yeah which is what you were talking
350.8 -> about there so i can actually tell you
352.24 -> so what we've done here is i've clicked
353.68 -> into uh one of these arrays and gone
356.24 -> into the retainers which shows you all
358.56 -> of the uh you know
360.32 -> the array is the the leaf node and now
362.32 -> we're going back up things we're holding
363.759 -> the references to that array and who's
365.919 -> holding a reference to the thing that's
367.12 -> calling the reference
368.639 -> so we can see the next thing on the tree
369.84 -> there is uh uintah clamped array and
371.68 -> then the next thing is image data so
373.199 -> there you go that's there's a big clue
375.039 -> and yes um
376.8 -> we've got these two 40 megabyte things
378.639 -> it's decoded image data it's the one on
380.88 -> the left which is the original image and
382.319 -> it's the one on the right which is the
384 -> encoded version then decoded and the
386.24 -> third one is 860k which is funnily
389.12 -> enough exactly the size of the
390.4 -> compressed image so it's probably that
391.919 -> one good eyes yes that is the encoded
394.56 -> jpeg so that's the three and you know
397.6 -> with app knowledge we can look at that
399.28 -> and go that's fine working as intended
401.52 -> working as intended
402.96 -> so the next phase is to
405.52 -> close that
406.639 -> don't do a reload because we're looking
408 -> for leaks yes so just close it within
409.919 -> the app reload it and then do another
411.84 -> heap snapshot uh and at that point you
414.16 -> see oh twice the memory twice the memory
417.919 -> and again
419.44 -> some app knowledge comes into this
421.039 -> because that might be fine because it
422.8 -> might be doing some caching you might be
424.24 -> you might have a way to go back to the
425.84 -> previous image you've got to keep it in
427.199 -> memory yeah maybe um but we know we
429.44 -> don't do that we do have some caching
431.12 -> but we know the caching is gone when you
432.56 -> press that yeah x
434.479 -> uh
435.36 -> so yeah as you saw in the summary right
437.12 -> so i guess you could do a comparison
439.84 -> that is what i'm going to do um so yeah
442 -> we can see we've got like a lot more of
443.52 -> those array buffers than we had before
444.96 -> we had uh three before we now have six
447.12 -> so it's just a comparison to snapshot
448.479 -> one or snapshot 2. so this is just the
450.08 -> raw snapshot 3 right now oh but let's
452.56 -> let's take a look let's have a you know
454.16 -> compare it to snapshots oh you can
455.759 -> select which one to compare to yes and
458 -> and so we can see now that there's some
459.84 -> stuff being created some stuff being
460.96 -> freed but we're still ending up with
462.319 -> more than we intended
464.56 -> this is not
465.919 -> really a useful view because we we know
468.319 -> that there are these six array buffers
470.639 -> still in memory
472.479 -> but we really want to know
474.4 -> well some of those we need because
475.36 -> they're on screen like the images are on
477.28 -> screen what we want to know is like
478.8 -> where are the ones that probably
480.4 -> shouldn't be around anymore and yeah i
482.4 -> mean the fact that we have it looks like
484 -> the ones at the bottom are the ones that
485.44 -> are being freed so two 40 megabyte
487.84 -> things were free good because of
489.599 -> probably the previous image we didn't
490.8 -> want those anymore and yet four forty
493.039 -> megabytes one are being created that
495.12 -> seems like two too many yes absolutely
497.36 -> and so what i've done here is i'm now
499.28 -> showing the objects allocated between
501.199 -> snapshot one and snapshot two
503.12 -> that are still around in snapshot three
506.96 -> okay yeah so these are the ones that we
508.8 -> would expect to be gone
510.639 -> because they were created you know for
512.24 -> that first showing of the image but they
514.399 -> are still there for snapshot three so i
516.24 -> didn't know this tool could do that and
518.32 -> yeah sometimes you just want to use the
519.919 -> the other kind of comparison but this
521.36 -> this really narrows it down to the ones
522.64 -> that we should be good because if we
524.08 -> know again with that knowledge like
525.76 -> everything created between snapshot 1
527.36 -> and snapshot 2 should not exist once we
529.6 -> go back to the landing page and start
531.12 -> over that's a big red flag absolutely
533.92 -> yeah so now it's trying to find out
535.839 -> where you know why are they there yeah
538.08 -> where did they come from
539.6 -> yes and so again we can click into it
542.16 -> look at these retainers which shows all
543.6 -> of the things that are holding on to
544.64 -> that in memory we're seeing it's image
546.48 -> data we saw that before write compressed
549.36 -> they
550.16 -> we know that that's a term from within
552.24 -> squish's source code so that yeah that
554.64 -> all makes sense
556.56 -> and there is one red flag there in that
558.48 -> list for me
559.92 -> and that is
561.519 -> detached html element
564.88 -> so a detached html element is an html
566.8 -> element that's no longer in the document
569.519 -> and that
571.04 -> isn't necessarily a bad thing you could
572.48 -> have like a menu in your app yeah that
574.399 -> you put in the dom and the user clicks
576.08 -> the menu thing and then when they click
577.36 -> away you take the dom element out but
579.12 -> you hold on to it for later yeah but
581.12 -> again a bit of app knowledge comes into
582.56 -> play here i know we don't it shouldn't
584.8 -> so this makes me think that we probably
586.32 -> hold a reference to the storm element
588.08 -> and one of our components states
591.12 -> and don't
592.16 -> hey you don't have to guess we've got
594.08 -> tooling now oh so what i would do is try
596.64 -> and find out which element this is and a
598.399 -> handy way of doing that is similar to
599.92 -> what you've seen in other parts of dev
601.76 -> tools you can right click and go uh
604 -> storage global variable
605.92 -> and there it is
607.04 -> and it's our two-up
608.72 -> customer
610 -> it sounds good element so that's the one
611.6 -> that's got it shows the image either
613.12 -> side and you swipe either side
615.04 -> and so it's like right
616.56 -> and again that confirms to me we don't
618.48 -> catch those
619.76 -> no they really shouldn't
621.36 -> be around from a previous
623.76 -> run yeah
625.12 -> so something happened here that caught
627.04 -> me out when i was debugging this for
628.959 -> reals is
630.72 -> at this point
631.839 -> it is useless to do another heap
633.36 -> snapshot and do more testing
635.44 -> because i have just stored something as
636.8 -> a global variable
638.24 -> yeah and that will mess with the results
640.16 -> same with console logs like if you're
641.839 -> doing console logs it's going to
643.6 -> it it's going to create memory leaks
645.44 -> because those things have got to stay in
646.64 -> the console and be unfoldable yeah
649.44 -> exactly so all right let's try and find
651.68 -> out where this where this turf is
653.36 -> why is it there
654.64 -> uh so again you want to sort of dig
656.48 -> further and further down or like you
658.24 -> know towards the root of the tree there
660.24 -> are these internal nodes those are c
662.72 -> functions within chrome right apparently
665.04 -> we might get those named at some point
666.56 -> but they're all called internal node
668.079 -> right now which is very very unhelpful
670.64 -> but before that there is va event
672.48 -> listener and we know what event lessons
674.959 -> are
676.16 -> i'm assuming yeah and just above that is
678.72 -> a link that we can press to some code
681.76 -> and that takes us here
684.48 -> one key down on key down sounds like an
686.72 -> event listener is this all urus
689.839 -> to tell me that a pr that i merged and
692.079 -> reviewed
693.12 -> introduced the memory league yep but
695.04 -> it's okay because there's another one
696.32 -> that i i merged that caused the same
698.24 -> problem and we'll look at that in a
699.44 -> second but yes we can see that here
701.519 -> we've got a window add event listener
703.04 -> key down uh and that is the source of
705.519 -> our leak
707.12 -> the problem here is is that this
708.56 -> listener is on the window object
711.12 -> and that's going to continue to fire
712.399 -> even if the element is gone because it's
714.32 -> on the window
716.32 -> so you know we create this two-up
718.56 -> element we take it away and when you
720.88 -> press keys it's still firing that event
723.2 -> and we do the
724.64 -> trick i think where this on key down
727.279 -> gets bound to this so we don't have to
729.92 -> worry about retaining this it's it
731.76 -> doesn't but it has a closure to it it's
733.68 -> an arrow function it's an error function
735.519 -> okay same same deal then okay so the way
737.36 -> of fixing this and apologies this is
738.88 -> because this is a real world case it's a
740.48 -> real world bug squish is written in
742.24 -> typescript
743.279 -> apologies if you're not used to
744.56 -> typescript but it's
746.16 -> it's javascript it's mostly javascript
748.72 -> uh this is our constructor for our
750.48 -> custom element for the two-up
752.16 -> um we're gonna go and find out where
753.76 -> that that event listener is uh it's
755.76 -> further down here uh in the constructor
758.16 -> for the for the event for the for the
759.76 -> element
761.519 -> uh this is with custom elements this is
763.68 -> a bad place to be putting an event
765.2 -> listener um because what we want to do
767.519 -> is we only need this listener when the
769.04 -> element is in the document we should do
770.399 -> it on it on
772.56 -> attached callback attach callback
775.2 -> connected callback connect to callback
776.56 -> close it's been a while i just realized
778.24 -> since i've written a custom element
779.839 -> shame on me no it's i had to look this
782.079 -> stuff up as well so i think we already
784.24 -> have a function for that there we go
785.36 -> connected callback so it is just moving
787.6 -> uh the the listener there
789.519 -> but then we need to do the reverse
790.959 -> disconnected don't we we need
792.639 -> disconnected callback which is when it's
794.32 -> taken out of the document so there it
796.399 -> goes and uh if you copy and paste a lot
799.2 -> like i do make sure you change it to
800.56 -> remove event listener i have created
802.56 -> bugs
803.76 -> where my disconnected thing is actually
805.2 -> just adding another listener
806.88 -> do that and that is the problem well
809.04 -> solved uh
810.959 -> the right thing to do is to confirm that
812.399 -> by going back into your app hit refresh
814.639 -> pick up the new code and then just uh do
817.6 -> the same thing open the image heap
821.04 -> close the image
822.48 -> open the image
824.079 -> heap
825.6 -> easy as that
826.959 -> just remember those steps but it's still
828.88 -> twice as much memory yeah still twice as
830.48 -> much it's because it's not fixed is it
832.399 -> no uh it is fixed like
834.72 -> when i first saw that i was like well
835.92 -> either that
837.199 -> wasn't a problem or there are more
838.959 -> problems
840.079 -> i can tell you now there were more
841.12 -> problems great so
843.12 -> we're back here again
845.04 -> same business interesting because now
846.88 -> the the retainer chain
849.04 -> that just sounds like something that the
851.199 -> dentist puts in your mouth
852.88 -> but yeah the retainer change should be
854.399 -> different now shouldn't it it is going
855.68 -> to be different so we're going to look
856.88 -> at the same array buffer
858.8 -> and there is no detached html element
861.76 -> there so we have sold weight problem a
864.48 -> small win
865.76 -> with zero effect
867.6 -> but again we're now just doing the same
870 -> thing i have a quick question then
871.44 -> actually so this the the chain of
873.519 -> retainers
874.8 -> is obviously
876.079 -> a chain here but multiple elements can
879.44 -> be holding a reference to the same leaf
881.76 -> can we see all of them yes you scroll
883.199 -> down you'll see them all okay but
884.639 -> sometimes some of them are false uh
887.519 -> because well because some of them will
889.04 -> have a reference to it but it would have
890.32 -> otherwise been collected
892.639 -> so sometimes you need to find the one
894 -> that is actually the real retainer it
895.6 -> normally does a good job of making sure
896.959 -> it's the one at the top not always okay
900.32 -> but again it's just looking at it and
902 -> sometimes it's just finding out like
903.519 -> where is this
904.8 -> where is this stuff so clicking through
906.56 -> some code this is a preact component
908.24 -> this time not a web component
910.639 -> looking at the constructor isn't helping
912.16 -> me at all figure out it knows roughly
914.32 -> where it is but it's not helping me
916.56 -> we've got again i felt like this line
918.16 -> wasn't very significant
920.16 -> but it told me what component it was in
921.68 -> but yeah it was insignificant it was
923.279 -> just telling me it's this is an instance
924.639 -> of this class okay um oh okay yeah
927.36 -> further down we've got an event listener
929.36 -> there's a bigger clue
931.04 -> um
931.92 -> move around for this tool tip to get out
933.519 -> the way
934.8 -> and again here we've got on mobile width
937.04 -> change we've got an event listener here
940.399 -> um
941.36 -> again it's it's just a function so it's
943.44 -> finding out well where is that made into
945.68 -> an event yeah
946.8 -> and we've got with query add listener
949.519 -> um
950.399 -> which when i saw this like i then knew
952.079 -> what it was because i'm familiar with
953.36 -> this code but
954.56 -> uh you can chase it further add event
957.36 -> this is add listener so this is some
958.88 -> custom code no
960.959 -> this is
961.92 -> match media
964 -> and match media uses
966.079 -> uh you can use ad event listener um but
968.959 -> it it also uses ad listener and safari
971.839 -> doesn't support ad event listener or it
973.279 -> didn't at some point
975.44 -> at one point on stage in chrome dev
977.36 -> summit the last on stage from dev summit
979.04 -> i broke the app before going on stage
980.959 -> and it was because i replaced one of
982.32 -> these things from ad listeners at event
984 -> listener and it didn't work in safari
985.6 -> and everyone in the audience was like
986.639 -> not working on my phone that was why so
988.48 -> i just use add listener now even though
990.48 -> you'll see it draws a line
992.88 -> deprecated yeah because it's deprecated
994.88 -> that's why that's happening
996.72 -> uh with a preact component that's
998.24 -> actually fine there in the constructor
1000.079 -> but this is the same problem as before
1001.759 -> we've got a you know width query this is
1004.079 -> something that's happening on the window
1005.92 -> object
1006.8 -> but we're using it with a component so
1008.24 -> it's keeping it alive so i just need to
1010.8 -> do what i did before
1013.199 -> this is not a custom element this is a
1014.88 -> preact component so it's a different but
1016.48 -> like callbacks exist
1018.56 -> in this one it's component will unmount
1021.199 -> remove listener
1022.639 -> job done deprecated deprecated
1026.24 -> it works it's fine
1028.4 -> and so yeah this is it just uh keep
1030.4 -> snapshot
1031.76 -> close
1033.52 -> open again
1035.52 -> mirror signal
1036.839 -> maneuver hey look at that
1039.839 -> and it's sorted and that's brilliant
1041.76 -> once i saw that it's like oh okay here
1044.079 -> we go
1046.16 -> and yes both are very similar problems
1048.4 -> and event listeners are going to be the
1050 -> problem
1050.88 -> it is the cliche for me there's always
1052.96 -> dangling eventlessness yeah
1054.64 -> unintentional globals or event listeners
1057.36 -> uh it tends to be so yeah that was it
1059.84 -> that was that was problem solved we
1061.2 -> shipped it excellent
1062.88 -> um
1064.08 -> but
1064.96 -> you know what we've we've got uh i would
1067.84 -> say i've got a bias towards chrome you
1069.36 -> probably do as well because it's where
1070.559 -> the money comes from that pastes the
1072.24 -> builds um but i thought i'd have a look
1074.24 -> at the similar tools in other browsers
1077.039 -> so this is firefox
1079.52 -> and it has a very similar menu
1082.08 -> uh it has a heap snapshot button there
1084.64 -> we go 18 megabytes you get this oh
1086.4 -> that's nice yeah
1087.84 -> it helps you really tell where the
1089.12 -> memory is spent very quickly this is big
1091.12 -> so we make it big yes
1093.12 -> oh there's an array buffer there's
1094.4 -> there's there's a bit of memory
1096.08 -> there's a similar listview
1097.76 -> i would say i
1099.2 -> i find these tools harder to use it
1101.52 -> could be biased but i find it really
1103.36 -> hard to find the attribution of what's
1105.36 -> holding on to objects in this
1108.48 -> especially when it comes to listeners
1109.6 -> and maps
1110.72 -> but here's here's a fun one
1112.559 -> so close it open again going to take
1114.799 -> another heap snapshot there
1117.6 -> oh no
1118.64 -> 160 megabytes
1120.4 -> well this is the fixed version this is
1121.919 -> the fixed version i thought you're going
1122.96 -> to show me walk me through this oh the
1124.32 -> whole thing no no no they're already
1125.919 -> making signals that this episode's
1127.2 -> getting a bit long so oh there's more
1128.72 -> leaks in firefox
1130.16 -> or are they
1131.84 -> do they not
1133.039 -> run some forced garbage collection they
1134.96 -> don't you have to go to about memory and
1137.12 -> press this hidden button
1139.12 -> minimize the memory usage
1141.2 -> minimize memory so basically it had
1142.799 -> twice never because the old references
1144.559 -> were still around nobody was holding on
1146.799 -> to them they are collectible but haven't
1149.039 -> been collected yet exactly and so i do
1151.52 -> that and we're back down to 80. so
1153.44 -> there's a gotcha there's something to
1154.4 -> watch out for if you're using this that
1155.679 -> makes sense uh and then finally
1158.24 -> safari in their timeline look they
1160.64 -> symbols not there at first i had to go
1163.2 -> into this this little edit menu and
1165.36 -> enable it but there's a memory
1167.6 -> line there
1169.84 -> but you you hit record and you start
1172.48 -> doing stuff and it will show you look
1174.88 -> there's some memory gone up
1177.84 -> same business again close it and open it
1180.559 -> again and oh
1182.799 -> memory is going up again
1184.48 -> so where's the forced garbage collection
1185.919 -> button ah there isn't one uh because
1188.96 -> this
1190.08 -> is a memory leak
1192.88 -> yeah
1194.32 -> so you get these little s things and
1196.72 -> they're heap snapshots you don't you
1198.08 -> don't get to choose when they happen but
1199.52 -> they always one always happens at the
1200.88 -> end
1201.76 -> which is useful um
1203.76 -> so we can dive into that here and we see
1206.16 -> something that's very similar to what we
1208.32 -> had in chrome again i find attribution a
1210.16 -> lot harder to deal with in this one
1212 -> versus chrome but in this case we've got
1214.559 -> a lot of canvas elements oh and it says
1217.44 -> there's a reader article something
1220.88 -> um
1222.32 -> you can click through to it and it gives
1223.52 -> you on the console
1224.88 -> uh so read article find the js elements
1227.28 -> with uh cached binding rect number 14.
1230.88 -> this is not our code no this seems like
1233.039 -> this is the reading mode
1235.28 -> i talked to a safari engineer and they
1236.799 -> went uh this is not your problem this is
1239.12 -> our problem we gotta go fix this now
1241.28 -> so
1242.159 -> so even though yeah i'm not used to
1243.919 -> these particular tools uh it helped me
1246.32 -> find an issue in safari um so they're
1248.799 -> going to say that now uh which is good
1250.88 -> yes and i feel it is part of their
1252.559 -> reader code because this this bug
1254.72 -> doesn't well they were able to do a raw
1256.96 -> webkit build and confirm you don't have
1259.12 -> a memory leaking webkit you do in safari
1261.2 -> because of
1262.72 -> internal safari things
1264.72 -> uh yeah and it wasn't even the only
1266.48 -> browser bug i found as part of this i
1268.32 -> actually found that resize observers
1270.159 -> leak in all browsers um always good
1272.88 -> although it's now fixed in chrome and
1274.72 -> it's fixed in
1276.64 -> webkit and i think it's fixed in firefox
1278.96 -> as well i'll put a link to that in the
1280.64 -> description if you want to see more
1282.159 -> about that
1283.2 -> but yes right now it's advisable to
1284.88 -> manually disconnect your intersection of
1286.88 -> servers and resize observers
1289.039 -> these slides took a long time to do
1290.48 -> because i kept running into actual
1291.76 -> browsers to solve but there we go um
1295.039 -> that is how to to fix
1296.88 -> some real
1298.24 -> in the wild
1299.6 -> memory leaks
1300.72 -> well yeah i learned something jake so
1303.2 -> did i
1306.72 -> so what i'm going to do here
1308.159 -> is i'm going to take a heap snapshot
1310.77 -> [Music]
1314 -> a heap snapshot a profile
1315.67 -> [Music]
1317.679 -> right
1318.64 -> let's see if i can go back and do that
1319.919 -> again
1320.45 -> [Music]
1322.159 -> i don't know

Source: https://www.youtube.com/watch?v=YDU_3WdfkxA