Plugging Memory Leaks With The Chrome Dev Tools - Ben Dilts

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
[Music] thank you cool so this is this will be a fun talk memory leaks are a big problem I yeah that's okay I have the technology so as you mentioned I'm Ben co-founder CTO at lucid software been there forever basically my entire professional career it's been fun we make lucid chart lucid chart is one of the biggest JavaScript applications on the web actually its typescript now and in the course of the last several months in an effort to get better tooling we we migrated on mass a half a million lines of JavaScript of typescript if you ever want to hear about that project that's a fun one too I'm sure that'll turn into a conference talk at some time but there's not a lot of projects of this size but it's it's it's enormously complex and we are seemingly constantly in a battle against memory leaks in fact we have an entire team of developers with whom I'm actually sitting right now dedicated to tracking down performance problems of all kinds including memory leaks and and tracking them and making sure that we understand what our performance is out in the wild on on on people's machines and then trying to improve it this is a quick snapshot that I took this morning from one of our performance dashboards where we actually measure memory usage JavaScript heap size usage in the wild so each data point here is one day's average memory usage in a browser tab it has been getting better my team has in fact been you know doing useful things I show this to you know everybody who questions that but this this we've seen like a 15 20 percent drop in average memory usage each one of those comes from three or four million data points from people's browsers out in the wild des and so it's it's really gratifying to see our ability to turn that down so before we get started on the tools themselves I want to do a quick review of garbage collection how it works very quickly prepare yourself for some serious oversimplification what we have is what are known as GC roots the garbage collector roots these are the places from which you can reference all objects in your JavaScript heap and those objects are typically the route would be like window or something like there's something that owns a window actually and then those have references out to all these other objects objects have references to each other and and the job of the garbage collector is to navigate that whole map figure out who has a path a retaining path it's called back to the root and keep those retain them and then sweep away everything that has no path to it regardless of if they have connections among themselves so this thing is fully automatic happens mostly in the background so well modern JavaScript virtual machines will have a generational garbage collector that sometimes runs in a separate thread and sometimes blocks show UI thread but regardless it's it's a process you mostly don't have to think about right you use things you throw them away they get garbage collected all of my memory problems are over right wrong it turns out that memory leaks are really really easy to cause in any environment including JavaScript how can you leak memory that doesn't get automatically reclaimed well you could add an event listener to to some Dom element from your class and then you think you've thrown away all the references to that class but the event handler is still in the list of event handlers on the Dom element and guess what that thing is part of your object in your object lives on you could set an object as data on a Dom element using something like jQuery you could you could have like this global cache saying I'm gonna remember so you know these calculated values and and and forget to clear that out and so even though there's a big piece of data that you're not using and haven't used in a really long time it can remain in memory basically indefinitely even things as innocent as a console log in the chrome tools when you do a console log it will log out a sort of navigable object so you can like expand it and look at its references and see what's downstream and so forth and that navigable thing continues to work even if you throw away all other references to the object so guess what you console.log something out it is stuck in memory forever until the user opens the dev tools and clears the log which is really unlikely to happen there's any number of ways that you can wind up with objects and so the question then becomes okay how do i how do I analyze a situation how do I know how much memory I'm using where it's been allocated from why it hasn't been garbage collected and sort of how it looks over time am i rapidly am I constantly allocating new memory or am I just allocating a ton of memory up front way too much and that's the source of my problem and there's a variety of tools in the chrome dev tools to help you with that and we're gonna walk through a quick example of each of these there's heap snapshots allocation profiles and allocation timelines heap snapshots are really the go-to these are the workhorse of the memory analysis tools in chrome this will tell you how like what objects are there right now so it takes a snapshot everything every JavaScript object that has not been garbage collected what is it what does it look like where was it not where was it allocated but what function was its constructor if any how do they reference each other how much memory to each of them retain but you can also compare these snapshots and say do I have new objects now that I didn't have before or what things were constructed or destructed or garbage collected since the last time I took a heap snapshot and also which things failed to be garbage collected so that's that's really the the honestly the go-to tool for most of this there's also allocation profiles which will tell you what code hats are allocating the most heap memory so what what code is making a bunch of garbage even if it's being collected garbage is not free right garbage costs CPU time to generate put it into the heap and then to be collected out of the heap at the end so the allocation profiles will help with that will show that allocation time lines are for objects that aren't yet garbage collected where were they allocated in the code and is my garbage being rapidly collected like it will actually show you over time here's the memory that's being allocated the amount of memory allocated during each one second interval or something actually a fraction of a second interval how much was allocated and how much of that has so far been collected so you'll see this sort of stream of blue and it'll slowly peter down to gray and empty out as the garbage is collected from from older times so now is the fun part it is demo time so I mostly agreed to do this talk because it gave me an opportunity to write an asteroids game on company time the I needed an example application with an amount of code that would be a sort of understandable that we could look at and analyze together and so I made this yeah now everybody knows that the best strategy oh is to stay still because otherwise it is really hard to reason about but you can also move in here here we go yes okay so what we have here is a pretty simple game being played on the canvas and I'm gonna give you a quick walkthrough of the code in here well Mike is questionable okay what you have is you have this thing the button this is just a menu that's a button starts the game construct the new game object game object in turn constructs a player adds a canvas element to the Dom listens to things like the mouse move and mouse down and mouse up events starts with some random asteroids and then starts.this when you say start it starts this animation frame loop and then when we stop the game because you've been hit we end the animation frame loop and go back to the menu and the the game of course we just create it and start it and so when we check you back to the menu the game should be gone and garbage collected so first thing that I'd like to do is show you the place that they start is not actually in the memory tools I'll click on this performance tab and this is actually a new thing as the last couple versions of Chrome and this does a sort of holistic view of all the things that are taking up time and memory in your application and it will recorded over time so if we say all right we'll start recording this we run the game oh man I set this okay here we go all right so we stop and it'll go so what we have here is a profile of the JavaScript execution which is pretty fast this is not a complex game and I have a pretty fast computer and this down here is the memory heap size over time during the course of the games that I just played it is going in the wrong direction it is going straight up it's normal for this graph to go up because you generate garbage in a lot of ways even very innocuous ways like returning ad-hoc structures from functions you'd see it go up and sort of come down when you'd see this drop off as a garbage collector cycle ran and it would go up and it would drop off again but this is just a steady rise and so the first thing that I would do is I would go and I would take a heap snapshot to see what is there right now in memory because apparently there's a whole bunch of stuff in memory um if we come over here to the memory place we have the three different things that I mentioned we go to the heap snapshot and click sneak take snapshot and what we will see here oh I shouldn't I should note that I artificially inflated the size of these objects by putting a hundred thousand random integers on them so that they would show up because otherwise everything is just noise so small so we have here all of the objects that are currently in the JavaScript heap you can sort them in a number of different ways the retained size is basically the way to find the big stuff okay this is not just the size of the object itself but the size of itself plus everything that it retains a reference to that might cause those things to not get garbage collected and so we find near the top here we actually 5-game objects still in memory despite the fact that there's no game running and as far as I know nobody has a reference to the game and so the question then is where are these things now if you expand this you can actually see the individual instances right of this game object excuse me they're not five there's four of them this one is the distance that's from the garbage collector route how many references is it before it reaches these objects there are four objects in here if you click each one of those you can actually see its contents so you'd say oh well it's holding on to this array of asteroids and this canvas which is red because it's not in the Dom anymore but it actually still has a reference to it so that thing's not getting garbage collected but where is this object actually if we look down at the bottom it shows the retainers so here we say alright for this game it looks like from the window some sort of array something there's this code in this function that's holding on to it and actually if you hover over this you get a little hint that'll take you back to the code where this function is defined um and it'll actually show you this function is holding on to a reference to the game scene at this point I remember I used to be hooking Mouse events on the canvas element but I change it to the window because I wanted the mouse moves to continue to work when you are off of the screen because anyway so I changed the event listeners from the local element to the window and we never unhooked those and so this event listener is still here and it references this and this is the game right so this thing didn't get garbage collected so we're gonna fix this really fast we're going say this is really fun to try to to try to do this well um with a bandaid on my thumb well I'm trying to run the touchpad this is extra super awesome um also this is a really fun thing for demos I would never actually use this on my production systems but you can actually set up the dev tools to let you edit the files directly on your file system and then you just save and refresh so we take those ones you copy them down to our stop function and we change these to be remove it what event listeners and will refresh and we'll try this again okay we refresh the page we start the game we play we lose and then we go to the memory and we take another snapshot and the game is still there again we look at this there is another one oh yeah I said another event for the window resize right so this is the way that it works you can look at the retaining paths and you track them down and one by one you wind up squashing them right you say do I oh thank you I'm good at this guy's alright yeah I'm okay there we go um like I said this is how you convince me to come give a talk at this point no game left right we've successfully killed it all right yeah okay all right one down so so that's the that's the heap snapshots right there's also other things that you can do where you can say for example if I start another game and then we take another snapshot if you compare this one to the previous one oh come on no you're gonna refuse Oh curse of the demo here the no you don't so you click you can't select them both all right uh-huh don't try this real quick take one take another you can say wow I take it back that drop-down has an item in it called comparison and and it will actually show you the ones that are yeah no it's not so and actually none of them are working this is sort of amazing um let me kill this so I'm gonna try this again and take one and take another and hey there it is good you get to kill them okay but you you oops right the idea is that you can take a snapshot and you can get into a state where you believe that the memory usage should be very similar and then you can take another snapshot and compare them so there I was at the menu here I've played a game I'm back to the menu I can take another snapshot and I can say comparison and this one will compare to snapshot two and it will say all right what's changed since then and it will show you the Delta like how many more or fewer of this kind of object are there then there was during that other snapshot and so that's a good way of saying for example when we're in lucidchart you go from one page to the other page back to the first page back to the second page back to the first page and we'll do a snapshot before and after and say well having gone somewhere else in your document and coming back we should have discarded all of the stuff that we generated in order to render the other page by the time that we've come back and that's that's gonna be a very effective way of saying you know this should be about the same as the previous snapshot and find those leaks okay all right so that's snapshots the next thing is allocation profiles and allocation timelines and I'm going to show the timeline first because it makes sense in the in the context of this application so if I start this allocation timeline and I start the game and I start shooting things um you'll see you see the blue up there those are objects that are that have been generated there you go and I'll just stop it okay the blue objects have been generally actually the entire height of those little bars is the amount of memory that's been allocated the blue portion is the part that has not yet been garbage collected okay and what you can actually do is you can select a portion of this like this and say all right what got generated here that has not yet been garbage collected it can't show you the objects that have been garbage collected because they have been garbage collected but it can show you that things that are there that are still there and so you know if we we do this again we start the game oh right I'm so good at this guy's here you oh I need to dodge okay and we stop okay what I see is a whole bunch of blue in here right now my earlier games got all garbage collected right those all got cleaned up fantastic but what's left over here remember I stopped it while the game was still running so they should be able to tell me while the game is going what stuff is still there like what's what's getting allocated that I'm not cleaning up and if we look at this like a little chunk here and you'll see like oh there's some new asteroids that got created and there's a handful of bullets that got created during this time period right and those objects were generated then and still haven't been garbage collected and just like the heap snapshot you can actually come into this and look at each individual one and say where is this actually this appears to be like bullet number ten in the the currently running game right this this gets to be more exciting when you leak a lot more memory but we just cleaned up however if we look at the performance here over time now we should be able to see that hopefully we have the healthy pattern yeah yes okay okay there we go oh man but we still have the steady upward climb so if you look at the blue bar here the blue excuse me the blue line graph you can see that a garbage collector I ran right here can make this Hey all right let me stretch it out a little bit you can see a garbage collector run happened right here right and there's small garbage collector runs because as I mentioned JavaScript modern JavaScript VMs run a generational garbage collector so things that have been allocated recently get cleaned up frequently and inexpensively and things that last a long time get put into an earlier generation and then those get checked less frequently and so we had a full garbage collector run probably that happened right here and we have a whole bunch of little bits of up and downs but we are steadily rising on the amount of memory usage that we have and so that's that's this is still sort of a mystery here but if we look back here really is we wound up with this long list of bullets that got generated there's never more than like eight of them on the screen at a time but you can actually look into the contents of these things oh yeah there's my hundred thousand pieces of junk data the you can look at these objects here except that the game has now been garbage collected I can't actually access them these things you can you can using this this is a hard this is a difficult case because things are happening rapidly but here you can actually navigate to the object itself in the console you could do here window what is that 26 whatever down to like bullets 18 and figure out where it is or or why it's still there it turns out in this case we're not clearing them off when they go off the screen right think they reach the edge of the screen and they just keep going off into infinity which again is a pretty simple fix but one that if you're not looking at a variety of different tools you might not realize if you just use the heap snapshots and you said here's what it looks like before game here's what it looks like after game and it looks good and you look at the timeline and you see the thing going like this and jittery you might be able to see it but you really need to use a variety of these tools in order to track down all of the all the issues that you might have you come back to the source and I think that we can actually clean these guys we can probably just make the move function return something and just kill these guys I'm like don't judge me I'm writing code fast okay and probably say well that also could have been my statement all right that'll work resolving host come on it's velocity mhmmm maybe this won't work as well it might be uh no I think it's good yes it turns out this is the reason why things like fast j/s work sorry for the aside while they wait for the Internet is everything the fast j/s is a thing that it that is a much faster implementation of built-in JavaScript things like for each is on arrays because they don't have to worry about things like user splicing stuff out they they'll it they explicitly don't make the guarantees that are made by the built-ins things like supporting sparse arrays and splicing things out of the array in the middle of the for each and so forth ok I'm not entirely sure if this refreshed but the spinny thing stopped going so at this point we should be able to come here clear out our data rerun this and try to survive as long as I possibly can okay close enough at which point we see this this is what a healthy memory graph looks like so you see there's some amount of allocations happening as time goes on because I made my bullets very very heavy um you get a actual noticeable gems for each individual one every hundred milliseconds but you have it going up and down and you have the garbage collector runs happening on regular intervals it's not taking up a ton of time doing the jaw doing the garbage collection so at this point we've made our application healthy now we've only covered two of the three big tools that are available to us in the memory tab the other is the allocation profile and what this will do is tell you where in the application the allocations are happening right where is the actual piece of code that is causing this thing to be allocated and so here if we start this one we say all right here we go oh man okay there you go okay stuff okay so what you have is you have just like you would have with a CPU profile where there's like how much time was spent in each method and you can do it in different ways like Bottoms Up like how much how many which methods had the most time spent in them directly versus which methods had the most time spent in them or the things that they called you can do the same thing here with memory allocation where you can say all right which things generated the most memory themselves and which things with their children in this case because I just allocate a whole bunch of junk memory um you can say all right who generated the most if we sorted by total size the tick function the frame running function turns out everything that does everything but if you look at the tree here you can say all right what's inside the tick function well we do a for each and we run for each on the bullets and we break the asteroid no we we're generating asteroids this is the and you have over here a link to the function itself and you say here's the write directly in this function is the place that we're allocating the big chunks of memory now this is a very boring example because very small I actually have a really large lucidchart diagram that I wanted to run this on for you this is a fun one this one has something along the order of six or eight thousand objects on it and and once in a while we get people sending us examples saying here's something that runs really slow maybe you could make it run faster we went through a couple of iterations on the memory tools with this particular document trying to get it down from it's outrageous amount of memory allocation during during load because what we found was when we ran the CPU profiler while loading up this big application with this big document most of the time was spent in the garbage collector actually it was something like 80% of the time spent loading this document was spent running the garbage collector over and over and what happened was we reached we got close to the amount of heat memory were allowed to have and so we were thrashing through the garbage collector where there's very little available space but it had to navigate essentially everything had to do a full generational search through all of the objects and a zero number of objects that you have reaches up into gigabytes then it turns into a real problem but this this one is a lot more fun here if we start the heap profiler when we refresh again I'm gonna give us a like sixty percent chance that this works since the Internet my machine here has been a little sketchy I would love it if this worked there we go this is a fun one um as I mentioned I sit on the team with the people who are full-time working on improving the performance of our application and and the things that are the most gratifying to work on are where there are really big really obvious performance problems and you can tell if you've made them better um you know we've we've gone through a lot of processes over the course of the last year of instrumenting performance and production we actually use zone j s which is this open source library that monkey patches every entrance point to JavaScript so anytime that you have a event that fires or a time out the fires or animation frame the fires or a WebSocket that gets new data or any way that you could possibly start executing JavaScript it actually passes through so you have the ability to look at every JavaScript execution that happens and we actually started measuring how much time do we spend in JavaScript out in production and you know on average for every one we did the same thing with memory where we said you know for certain browsers as long as the user hasn't turned it off and it's usually rounded to the nearest megabyte you can actually get the heap size of the JavaScript heap very quickly and we started reporting that data back as well which is what led into a lot of the things we're going to see here but ya know I think that we might be out of luck here resolving hosts I don't think you can see it there cuz oh well regardless this it's the allocation profile was the tool that actually resulted in us making this document that previously would crash out the browser after spending like 20 minutes trying to load into oh there we go made a document that presuming your internet works you know loads up in something like 30 or 45 seconds because it was generating so much garbage and it was interesting because it really was garbage it was not memory that we were using it was not it was not objects that were long lived we were generating data based on the partially loaded document and then we were generating again when it was a little bit more loaded and then we were generated again when it was a little bit more loaded and what happened was we generated something on the order of don't judge me like 3 gigabytes or three and a half gigabytes of data during the course of loading this document when in fact when it was done the whole JavaScript heap size was a couple of hundred megabytes and so something was clearly off and that's a really difficult thing to debug because you can't look at it at the end and say what do I have and how do I not generate it because that's not the problem the problem wasn't the stuff that I had the problem was all of the stuff that I built and then threw away and so what this allowed us to do was to look deep into our code and find that there we go and find the places where we were actually generating way way too much data and so here we have a much more interesting set of information where you say alright we're legitimately generating what's at the top about a gigabyte worth of data while this document is loading it used to be several times that but then you get to look at this and say alright what are what are the heavy things right there's this anonymous function that itself internally is generating a hundred and fifty megabytes of data during the course of loading this document like let's go look there and see what's in the what's in the code there's also a chart view here which is fascinating this is not the x-axis here is not time you can get the sort flame chart out of the CPU profiler and it will show you like over time who's who's eating up the CPU like what is the stack trace at this point in time where he took the snapshot on the CPU what we have here is a stack trace and the x-axis is the amount of memory that was allocated like when we reached a hundred megabytes allocated what was the current stack trace when we reached a hundred and one megabytes allocated what was the stack trace and so what you get is it it's scaled by the amount of memory that it generated not by the amount of time it took and so you're able to look at the big fat bars here and say Oh something something is going wrong here right re measure if new funds like we're remeasuring some text right and and we're generating 321 megabytes of data while re measuring all the text on this document which may or may not be reasonable depending on how many tens of thousands of words are in the document but but it gives you a target right it gives you the big fat target to go look at and say this is this is the the next place that I'm going to investigate okay I think that that's basically all that I had for today thank you everybody for your patience I think we're gonna take questions though so we have another ten or so minutes so if there's any questions I'm not sure if the plan is to pass around a mic but I'm happy to take any questions about this or basically anything else we got one in the back yep oh the JavaScript profiler so that's actually the old JavaScript profiler so the performance tab that I showed here is actually the official replacement for the JavaScript profiler however it does not have all the features of the JavaScript profiler and as right now basically my full time job is profiling the application I will take the one that still has all the features and the features that are missing in the new one are things like focusing in on our particular function so that if you take a large CPU profile and there's one function that you care about for example I'm trying to improve rendering performance I will do of actions on the document while I'm profiling and I'll stop and then I will focus on the the the render method and the things it does so that becomes a hundred percent so and it shows the percentage it'll say a hundred percent in the render function and here's all the different pieces because I don't particularly care about the amount of time that got spent responding to the xhr request and so forth but that feature is not yet in the performance tab and so I I'm not sure if the plan is to leave the JavaScript profiler available indefinitely or only until they reach feature parity or what but you can find it under the Hamburglar menu over here under more tools there's JavaScript profiler and it will actually make the the tab appear yeah question was is chrome the only browser I use for this stuff in practice it is almost the only browser that I use for this stuff periodically will have performance issues in other browsers unfortunately Chrome's dev tools have pushed other browsers to produce decent dev tools before chrome the best dev tools were actually an Internet Explorer which is ironic because they are awful the browser that is the dev tools are actually basically okay way before the browser was but now there's reasonably good tools everywhere Safari actually is the only major browser that has a instrumenting profiler instead of a sampling profiler so what we have here and in most places is every so often I think it's every 100 milliseconds they will take a stack trace write like what's the current stack trace and they use that to generate the data that you see in Safari what happens is they actually recompile all of the functions that you have in JavaScript and they measure the amount of time that is spent executing them now this is a problem because it changes that the performance characteristics of your application but what it gives you is the ability to measure the number of times that a function is called where there's no way of doing that with a sampling profiler and so if there's some place where I I worry that the problem might be that this function is just being called too often or that's right or that that's the thing that I'm trying to improve I will actually open up Safari on a Mac and you the profiler there so yeah there are tools there's there's different tools available but by far Chrome has the the best set of performance profiling stuff including memory profiling stuff yeah I'm sorry then last part again oh yeah so yeah that's a whole conference talk on its own I was gonna do it except that I yes okay question was what things do we measure in production what things do we measure in production and how do we turn that into actually fixing things with memory it's difficult because the only thing that you get is the current JavaScript heap size and you only get it for Chrome and it's rounded to the nearest megabyte and it's may or may not have had garbage collected however more than 50% of our users are on Chrome and so it's a big enough data set that for us it's sufficient to be able to look at things and and see real trends among our users for and we actually collect it once per minute so once per minute we actually ping home with the last minutes summary of performance data with it's just things like how much time was spent running JavaScript and tags on different JavaScript executions and in memory just one snapshot of saying here's the amount of memory right now if we've got that data and so we actually send it back once a minute we can actually look at trends over time per editor session so in the case of memory usage the first time that we put it in we had zero visibility into this before but I ran a linear regression on a half-a-million editor sessions against the time passage versus the memory usage and we were the heap size was growing on an average of one megabyte per minute averaged across all of our users and so if you were there for an hour it might have crept up from two hundred Meg's to 250 Meg's worth of memory usage and that was like the average across all our users so some of them were much worse than some of them were basically okay but that actually was interesting insight that we didn't foresee in terms of the JavaScript execution we can get a lot more data and so so what we do is we keep track of when JavaScript executes so like I mentioned with zone J's we can know when and when it starts and when it ends we also are able to keep track of micro tests promises and we say and we know users are not able to interact right like it's totally it's for one synchronous set of JavaScript execution where it's the tasks and all of its associated micro tasks we measure how long that took and then we bucket those and we say how many times during the course of the last minute was JavaScript holding the UI thread for 16 milliseconds or longer 50 milliseconds are longer 100 milliseconds longer quarter second full second or no longer and how much total time was spent frozen up for that threshold so we'd say how many 100 millisecond pauses which are like just enough for the user to be like okay like it it feels goofy how many times did that happened in an average minute and how much time did the user spent locked up for that amount of time during that minute and so we send that up and then we essentially dump that into a redshift database where we do a whole bunch of statistical analysis on it but we also tag them so the if it's each JavaScript execution during the execution we can we can fire tag saying like oh this was rendering like during this JavaScript execution we rendered a frame or during this JavaScript execution we like sent this xhr request to this URL or responded to and so those tags then get aggregated up and we can look at it from one day to the next or the next week or the next month and say all right which of these have moved has rendering got better or worse has like has generating the data for a document save started causing people to drop frames more than it has in the past right and so we're actually able to to look at this in some amount of detail and it's easy for us to add these kind of tags so we have this massive database now we are constantly running out of space on a redshift cluster actually mostly from this data but I smile because we've gotten fantastic data out of this and just in the last week we had there had been a performance regression that had been going for five or six weeks and we hadn't been able to figure out what it was but but we knew from the amount of tagging that we had done that it was from a set interval there was a set interval that was running and it had suddenly caused like the number of times that people froze up for a hundred milliseconds or more to go up by like 30% 40% something ridiculous but it was an untagged one we tagged a bunch of them but not this one and so we went through and tagged all of them in our code every single one and we released this update and we started watching the data and it was still untagged and then we realized it was coming from a third-party library like a third party thing that we had put on the page which we hadn't updated but they had updated and what they were doing was now causing like 20% of our total user pain in terms of performance and we were able to know that for certainty because of the the level of detail of the data that we were collecting so anyway I cannot recommend highly enough instrumenting in the wild to the degree that is you know that is possible or reasonable what you users performance looks like because you find stuff like this but like we never would have known right and our users were suffering so anyway that's the long answer yeah in terms of just generally helping with performance so oh let's see it's it's mostly the chrome dev tools frankly um like 95% of my job when I'm when I'm figuring out performance issues it's in the chrome dev tools as far as actually reproducing seeing the issue and fixing the issue if the chrome dev tools as far as internal tools didn't know what thing to fix it's basically what I described and that's that's my whole tool set yeah ah good question so a question is say you have a button with an event handler on it and then you like it somebody put an on click on the button and then we throw away the button does the button still exist that depends on what happened to the person who set the event handler okay so if if the object that constructed it that gave it the handler the the function that the onclick actually calls if if that function refers to objects that are still retained or yeah if then then the button will will remain there whereas if it's been thrown away it will be thrown away so sorry it's very difficult to explain in the abstract in the context of my game there was the cut there was the canvas right the canvas element it got thrown out of the Dom when the game was over it had a context menu handler on it right when you right-click it we like do a prevent default to make keep it from doing the standard context menu that one I did not have to unlistenable collect and to get the canvas to garbage collect and the reason is that the the the game itself had a reference to the canvas and that the the event handler had a reference to the game right the event handler was doing something to the game that solely reference to each other but there was nothing outside that was still being retained back to the window that was referencing either of those and so although they were connected to each other and interrelated pretty heavily as soon as we removed it from the Dom and throw away our references to the game it was all clean yeah I that's a that's a difficult question I know that there are there are coding styles that are intended to help make sure that that memory is dealt with appropriately in fact this hold language is built around the idea that if you code carefully you can do like you know static compiler based like go has doesn't have a garbage collector but you also don't do memory management because the memory management is actually guaranteed by the compiler because they can analyze your code in that depth so like there are ways of doing it in practice especially in JavaScript I I have yet to see someone do this successfully frankly like in terms of like is there a way of writing code that's gonna make it much less likely the biggest things to remember are you've probably screwed up event handlers that's the reality of it like if you're leaking out memory and my experience like more than 50% of the times that that's happened to me it's because I've leaked out event handlers and not just Dom event handlers like you have objects that fire events right like you can have things that have callbacks where you like telling this object please notify me whenever this event happens you know and and those those internal relationships you don't realise sort of how far that web goes and you wind up retaining a whole big chunk of your application that you didn't use before and so we use the the closure library and they have sort of this this set of classes for event handlers and disposable things and so forth that that help to be more explicit in your code about saying I'm done with this thing in fact we recently made it so that if you use one of the disposable objects and you call dispose on it we actually replace all of its entries with getters that throw an exception so if you ever try to use something that has been disposed in any way it will actually blow up at runtime in dev and and like that trying to be more deliberate about saying like let's clean up after ourselves and let's make sure that that we're rigorous about that has been helpful yeah Oh so okay so a question then was when you're looking at the the output here there's a whole bunch of like anonymous function I'm not on this function anonymous function anonymous function right and the the chrome tools are pretty smart about classes if you use and and not just classes but also you know prototype kinds of classes and like the chrome dev tools are pretty smart about it you can name your functions so if you have anonymous functions used to function space the name and then whatever for like anonymous inline functions and that that will give them a name so that it will show up in the in the whole set of dev tools we actually start from typescript and so the our code has already been transpiled by the time it makes it the browser even in dev but the typescript transpiler is pretty good about maintaining names and actually giving things names automatically to make sure that things like the dev tools work well but by and large putting names on your functions is the biggest thing but it's actually not as big a problem as you think because almost everywhere in the dev tools where you see anonymous function you can click through and see which function it's talking about so it's generally not a big problem yeah uh oh gosh um I turn off I turn off source maps they're turned off in my browser right now so source maps for those for underwear if you start with another language like typescript you transpile the JavaScript it there's it produces a either a separate file or a really big encoded comment at the bottom of the file saying in this output JavaScript like where which pieces of this line up to the original source code so that you can get things like stack traces from your original typescript files rather than from JavaScript and so the reality is it it's not worth the pain my experience actually on the whole source source maps have not gotten good enough for me to like using them it causes we had a lot of code and so you load up the the dev tool so you open the dev tools and the first time you go to the the source files it will lock for us for like 20 seconds or longer while it figures out the source Maps and then it never works as well as you want to you put a breakpoint it's like you you're seeing your typescript and you put a breakpoint and it may or may not stop exactly where you wanted it to stop and it caused enough pain on going which I turn them off I think most people in my team do yeah we do so we use the closure compiler so we use typescript 2 or we use the typescript compiler to go from typescript to JavaScript we actually use a project called sickle that was built by Google as part of a way to sort of a bridge it's like the closure compiler and then we we've actually written probably 20% of it to because we were probably the only big client of it outside of Google but then the closure compiler is by a far cry the best minimizer that exists in the market for for JavaScript but it does require a lot of work to work with but we have a so that's sort of our pipeline we start with typescript we go through the angular compiler and sickle and wind up with the closure compiler applause awesome thanks very much round of applause for Ben please [Applause]
Info
Channel: UtahJS
Views: 13,345
Rating: 4.9064326 out of 5
Keywords:
Id: Hr2vrhrNaRo
Channel Id: undefined
Length: 52min 46sec (3166 seconds)
Published: Wed Sep 27 2017
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.