Placeholder Image

Subtitles section Play video

  • [MUSIC PLAYING]

  • JOHN MCCUTCHAN: Hey, everyone.

  • I'm John McCutchan, and welcome to the Break Point.

  • And I'm here with Loreena Lee.

  • LOREENA LEE: Hi, I'm Loreena Lee.

  • JOHN MCCUTCHAN: So what do you do at Google?

  • LOREENA LEE: I actually work on Gmail, and I'm focused

  • primarily on performance, so making it faster as well as

  • making sure we're using the right amount of memory.

  • JOHN MCCUTCHAN: Nice, well that's good.

  • Good thing you're here, because we're here today to

  • talk about understanding the way memory works inside

  • JavaScript and how to profile your usage of memory inside

  • Chrome dev tools.

  • So I'm going to spend a little bit of time talking about the

  • conceptual material for how JavaScript manages memory.

  • And then Loreena is going to show us a really cool demo of

  • using Chrome dev tools.

  • So JavaScript variables can be of four primary types--

  • the boolean type, which just true or false canonical

  • values, the number type, which is any double precision

  • floating point number, the string, which is a UTF-16

  • encoded character array, or an object, which

  • is a key value map.

  • For those of you familiar with JavaScript, this

  • is very basic stuff.

  • But we're just going to start from scratch and build up.

  • So objects are built around key value mapping.

  • So the key goes in the square brackets.

  • And this is always a string.

  • No matter what you put in it, it's going to be

  • coerced into a string.

  • And then use that as the look up into the table.

  • And then for value, you can store any JavaScript object

  • inside of the value.

  • So a key fundamental concept of memory and JavaScript is

  • the object graph.

  • So we're looking at a whole bunch of circles and lines on

  • this slide.

  • But let's start from the left at the blue circle.

  • This is the root object inside the memory management system.

  • This is not something that you can explicitly manipulate or

  • do anything with, but this is just where every object that

  • you create descends from.

  • And so this is called the root.

  • And from the root, it references global variables

  • and other global state that's available to the browser.

  • The red objects are object variables.

  • So these can reference other variables.

  • And the green circles are scalar variables, like a

  • boolean or a number that can't reference anything else.

  • And you can see the green note at the end there, on the upper

  • right part of the screen with the yellow arrow, this is the

  • terminating node in this part of the object graph.

  • So objects have a concept of a retaining tree.

  • And this is the paths along the graph that are keeping the

  • object from being classified as memory.

  • So on the slide right now, you can see a green node.

  • And let's look at the retaining tree

  • for this green node.

  • So the retaining tree is this yellow node here--

  • the root node--

  • as well as this other path from the root to the other

  • yellow node as well.

  • So the object actually has two paths that are keeping it

  • pinned into memory.

  • If both of these paths are terminated, then the object

  • becomes garbage and eventually is collected.

  • Objects have two sizes.

  • They have a shallow size, which is just the size of the

  • actual object.

  • And this is usually a very small constant value.

  • I think on my system, an object is 36 bytes.

  • All of the variables that the object references are

  • accumulated together.

  • The sizes of those objects are accumulated, and this is the

  • retained size of an object.

  • This is the amount of memory that could be freed if this

  • object was turned into garbage.

  • LOREENA LEE: If you go back to the previous slide, we can see

  • the retained side of the root node would be basically the

  • whole graph except for those two disconnected

  • nodes in the middle.

  • JOHN MCCUTCHAN: Yes, which are garbage.

  • So from the root node, the retain sizes is the size of

  • everything that's still reachable.

  • So what exactly is garbage?

  • Well, the definition of garbage is any variable and

  • all variables which cannot be reached from the root node.

  • So in this diagram here, I've highlighted the two nodes

  • which are garbage.

  • The red node is referencing in the green node, but there is

  • no path from the blue root node to that red node, making

  • both the red and the green node into garbage.

  • So garbage collection happens in two phases.

  • First, the graph is scanned, and all garbage is found.

  • So we already know the garbage in this graph was the red and

  • the green node.

  • And then this memory is returned to the system during

  • the collection phase.

  • So it's important when optimizing for performance and

  • memory usage to understand the cost model

  • for allocating memory.

  • So every time that your JavaScript application calls

  • new, it reserves memory from something called the young

  • memory pool.

  • So memory is split into young objects and old objects.

  • The v8 internally decides when to promote an object from the

  • young memory pool to the old memory pool.

  • You don't have any control over that, but when you call

  • new, you're going to be scooping up memory from the

  • young memory pool, which is very cheap.

  • It's actually incredibly fast until the on memory pool runs

  • out of memory.

  • And at that point, the young memory pool is scanned, and

  • all of the garbage is collected, freeing memory,

  • making it possible to allocate new objects.

  • And this could take milliseconds.

  • So for interactive applications, you really want

  • to be careful about how you allocate objects and what the

  • patterns are, and how long you hold onto them, particularly

  • for a game.

  • You pretty much need to be able to do a frame with zero

  • allocations, because inside of a frame, you have 16

  • milliseconds to compute the state of the world, render it,

  • and take input handling, play sound.

  • If half of that time is taken up by garbage collection, the

  • game's not going to be very much fun.

  • So in summary, all variables that you have in JavaScript

  • are part of the object graph.

  • And the only inner nodes in an object graph

  • are JavaScript objects.

  • They're the only type of variable that can reference

  • other variables.

  • And objects have two sizes--

  • the shallow size, which is just the size of this the

  • object itself and then the retained size, which is the

  • size of the object itself plus all of its

  • descendants shallow sizes.

  • So all variables that cannot be reached from the root are

  • classified as garbage.

  • And when v8 decides it's an appropriate time, it will do a

  • garbage collection phase, freeing up memory and

  • collecting all the garbage and giving it back to the system.

  • So allocations are really cheap until the young memory

  • pool runs out of memory.

  • At that point, a garbage collection is forced, it's not

  • just done at an opportune time.

  • So you have to watch out for that in interactive

  • applications.

  • So Loreena, do you want to give us your demo?

  • LOREENA LEE: Sure, so just a little bit of basics about the

  • Chrome dev tools.

  • So we'll talk about how you can use the dev tools to

  • profile what's in your heap at any given time, and then also

  • to find situations where you may be leaving around memory

  • allocated that you don't need anymore.

  • So in general, the garbage collector should be cleaning

  • up after you.

  • But there are certain situations, which we'll see in

  • a little bit, where things may not get

  • cleaned up as expected.

  • So a little bit of his background on the dev tools.

  • We can use these now.

  • There are multiple tabs, and we're going to go through this

  • in an example.

  • But first, you want to if you have a suspicious action, so

  • you see that your memory is growing, or you think that

  • your application is slowing down for some reason or

  • another, and you think that memory might be the situation,

  • you can use the Timeline tab to perform the action and see

  • what's happening to memory.

  • So we can see if it's growing over time.

  • And if so, then we can say, OK, now we need to dig a

  • little bit deeper and see what's happening in the heap.

  • So we can use that to capture a heap snapshot, which will

  • show you all the objects that are in the graph that John

  • just talked about.

  • It does not capture scalar values, which were the green

  • nodes-- green nodes?

  • JOHN MCCUTCHAN: Yes.

  • LOREENA LEE: Green nodes in the graph that we saw.

  • But it does show you all the JavaScript

  • objects that are allocated.

  • There are four views of a snapshot.

  • And you'll see these in the demo as well.

  • There's the summary view, which shows you everything in

  • the heap, and you can apply a filter on the entire graph to

  • show only certain things.

  • And I'll talk about that in a little bit

  • in the demo as well.

  • And then there's a comparison view, where you can view the

  • differences between two heap snapshots.

  • So you take one snapshot and then take another one and see

  • what happens to memories.

  • Did more things get allocated?

  • Did a bunch of stuff get collected?

  • What's going on there?

  • There's a containment view, which is a bird's eye view of

  • the app's overall object structure.

  • So John mentioned a little bit about memory

  • versus retained memory.

  • And so in the containment view, you can see more easily

  • what the retained memory is.

  • And the DOMinator's also has a different

  • view of the same summary.

  • JOHN MCCUTCHAN: Yeah, so the summary and the comparison

  • view are sorted and organized around the objects

  • constructor, whereas the containment view is organized

  • starting at the root.

  • So it captures the structure of the object graph.

  • LOREENA LEE: OK, so we're not going to cover the container

  • and DOMinator's view too much in this demo.

  • But there's some really great documentation online at

  • developers.google.com, where you can see some nice demos

  • that show you exactly what you can see by

  • these two other views.

  • So we talked about comparison view and how sometimes you can

  • take two snapshots to find leaks.

  • But we're going to talk about a case where two

  • is not quite enough.

  • Some other good tips to know, though, are, you should always

  • do these experiments in an incognito window.

  • You want to make sure that you're in a clean room

  • environment.

  • You don't have your extensions that may be interacting with

  • your app in a way that you don't understand or

  • you don't even know.

  • So something these third party extensions do all sorts of

  • crazy things to memory, and you want to make sure that

  • those aren't influencing your results at all.

  • JOHN MCCUTCHAN: Yeah, just to repeat that, any browser

  • extension that is loaded will be part of the heap snapshot.

  • So you're not just looking at your code.

  • You're also looking at any extension that happens to be

  • loaded at the same time.

  • So an incognito windows is a quick way to avoid loading

  • your extensions.

  • LOREENA LEE: And then you want to get your bearings.

  • So on the heap profile page, you'll see that when we show

  • the heap, there's a lot of stuff in the heap.

  • Basically, anything in parentheses you should just

  • filter out of your brain for a little bit.

  • You can just ignore them.

  • A lot of the things are also going to be dimmed, and those

  • are system allocations that we can't really

  • control from your app.

  • So those also should be ignored.

  • And then the other thing to note is, when you click that

  • heap snapshot button, a full garbage collection right

  • before you click it before the heap is profiled.

  • So you can assume that anything that v8 decided that

  • it should GC should already be cleaned up.

  • So let's move on to the demo.

  • Let's see.

  • Where are we?

  • So we have this quick little demo.

  • It really doesn't do a whole lot.

  • There's one button.

  • And when I click it, it will start filling up a cache.

  • So I have a cache of five items that, whenever I click

  • it, it fills in the cache of five.

  • So the size is five.

  • JOHN MCCUTCHAN: So what happens to the entries that

  • are already in the cache?

  • LOREENA LEE: When I first click it, there's

  • nothing in the cache.

  • So what we want to do is, in theory, when we flush the

  • cache-- so by filling it with new stuff--

  • in theory, all the things that were in the cache before

  • should be evicted.

  • And in theory, we think that they should be collected.

  • Let's find out what happens.

  • So let's go ahead and refresh just so we know that we're

  • loading everything from a clean state.

  • Let's go back to the timeline.

  • I mentioned this earlier.

  • JOHN MCCUTCHAN: Yeah, that would be great, actually.

  • LOREENA LEE: So we can go to the timeline.

  • Let's say that we think that this is causing a memory leak.

  • So we're going to go onto the memory here.

  • And we're going to click Record, which is this gray

  • circle at the bottom.

  • JOHN MCCUTCHAN: It will be red.

  • LOREENA LEE: And now it's red.

  • So we're going to go ahead and say, let's do some work.

  • And we'll just do it a few times, click it a few times.

  • And then there's this little button here that looks

  • like a trash can.

  • And that will force a garbage collection.

  • So let's just force it and say, OK, maybe it now can

  • clean up whatever it was that I left behind.

  • So hopefully, all those things that I added to the cache that

  • had been flushed out, pushed out of the cache should be

  • cleaned up.

  • And we'll go and do some more work.

  • So you can see that at the top, the memory is growing.

  • So you see in blue there that there's some new

  • memory being allocated.

  • And when I click the garbage can, it seemed to have dropped

  • a little bit but not quite to the baseline.

  • So let's go ahead and stop this.

  • And if I go and click anywhere on the top here, I can look at

  • a specific part of the graph.

  • And I can widen this window here to view whatever portion

  • of the graph I want to see.

  • So down below, you see this green line that kind of looks

  • like a stair step.

  • And each time I push the button, that is the number of

  • DOM nodes that are allocated.

  • So you can see that it goes up.

  • JOHN MCCUTCHAN: So it looks like we're leaking DOM nodes.

  • LOREENA LEE: Well, it looks like we're

  • allocating DOM nodes.

  • We aren't necessarily leaking them yet.

  • So we don't know.

  • The garbage collector may not have kicked in yet.

  • And so they wouldn't get collected.

  • JOHN MCCUTCHAN: Oh, that's right.

  • We're not looking at the part of the graph after you

  • clicked, garbage.

  • LOREENA LEE: Exactly.

  • Let's bring it out over a little bit wider so we can see

  • what's going on.

  • And right around where the dip is in the blue line is when I

  • click the garbage button.

  • And we don't see it going down.

  • So that is the problem.

  • And if we widen it even more, where I clicked a little bit

  • more, you can see there's more stair steps up when I click

  • the button.

  • So we're pretty sure we have a leak.

  • JOHN MCCUTCHAN: This looks pretty suspicious.

  • LOREENA LEE: And on the left, there's the DOM node count.

  • So it'll tell you what the range in DOM nodes allocated

  • for the range that you're looking at.

  • So from here, we started at 15.

  • And now we've got 92.

  • So that number never went down.

  • We see that the green line pretty much never goes down.

  • So now we can go back to the profile page.

  • And let's refresh again, so we can flush the cache, start

  • with a clean slate.

  • And now we're going to take a heap snapshot.

  • So take a heap snapshot, and click Start.

  • So it's super fast, because this is a

  • pretty lightweight thing.

  • So this is our first snapshot.

  • JOHN MCCUTCHAN: So I see a lot of things in parentheses right

  • up at the top.

  • LOREENA LEE: So we're going to go ahead and ignore those.

  • These are compiled code, system arrays, things that we

  • really can't control.

  • So go ahead and ignore those for now.

  • And we'll just scroll down a little bit.

  • And you can see that we've got all sorts of

  • stuff in our heap.

  • JOHN MCCUTCHAN: So everything in this table is sorted by the

  • constructor call.

  • So it's not the variable name or the path that you could

  • follow to get to the variable.

  • It is the constructor.

  • LOREENA LEE: So at the top, it says, class filter.

  • So if you wanted to search for a certain thing--

  • I know that we have our caches of objects called stuff.

  • So if I type in, stuff here--

  • JOHN MCCUTCHAN: Very descriptive.

  • LOREENA LEE: Well, there's nothing here, because we

  • haven't allocated anything yet.

  • So that's expected.

  • So let's clear this out.

  • And let's do some more work--

  • or do some work, we haven't done any yet.

  • And we're going to click and collect another snapshot.

  • So if we click on this snapshot now, you can see that

  • we've got a 1.3 megabyte heap, whereas before we had a 1.2.

  • So now we get to those different views we talked

  • about earlier.

  • So right at the bottom here, it says, summary.

  • And right now, we're looking at a summary view, and we're

  • showing all objects in the view.

  • And so that's why we see this long, long list of things.

  • So let's go to Comparison View.

  • Let's say we want to know, what's the difference between

  • snapshot two and snapshot one when we click that button?

  • And so it says we're in Comparison View, and we're

  • comparing with snapshot one.

  • And so these are the differences.

  • And it's a much shorter list, because we filtered out now.

  • JOHN MCCUTCHAN: We really culled a lot of it.

  • LOREENA LEE: So these are now showing us only the

  • differences between one and two.

  • So you see we have this, stuff object.

  • And I told you that the cache was a five item cache.

  • And so there are five items.

  • And way over here, you can see, if we highlight the

  • stuff, the delta between snapshot two and snapshot one

  • is plus five.

  • So there's five new objects of stuff, which is exactly what

  • we expected.

  • JOHN MCCUTCHAN: So this column here is the number of objects

  • that were created of that type, this is the number that

  • were deleted, and then this is just the sum of the two.

  • LOREENA LEE: Correct.

  • So this is expected.

  • We have a cache of size five.

  • We push the button.

  • We filled the cache.

  • So this is what we were saying earlier is that OK, well,

  • there's no leak here.

  • We expected to see five.

  • There's five.

  • So now we need a third one.

  • So let's try that again.

  • Let's do some work and go ahead and

  • collect a third snapshot.

  • Memory is going up.

  • We are at 1.4 now.

  • And if we diff with the second one again, we'll see that

  • there are--

  • oops, there we go--

  • JOHN MCCUTCHAN: Another five stuff for--

  • LOREENA LEE: And that's fine.

  • We allocated five.

  • But we didn't delete anything.

  • So, hmm.

  • So if we look back in the Summary View here, we'll see

  • that there are now 10 objects of type stuff.

  • JOHN MCCUTCHAN: And this matches what we saw in the

  • timeline graph, where we were never seeing anything go down.

  • It just kept going up on a fixed size, seeing

  • the stair step in.

  • LOREENA LEE: So another thing that's great to see now is

  • that we can go into the Summary View again.

  • And we can say, show me the objects that were allocated

  • before snapshot one.

  • And that will show you that.

  • And there shouldn't be any stuff in this, because we

  • hadn't filled any cache.

  • But now you can say, show me the objects that were

  • allocated between snapshots one and two.

  • JOHN MCCUTCHAN: So we should see five stuff.

  • LOREENA LEE: So we should see five things that were

  • allocated between snapshots one and two.

  • And those things we expect have been flushed out of the

  • cache by the time that we did the third snapshot.

  • And so if they're still hanging around in the heap in

  • snapshot three, that's probably our problem here.

  • JOHN MCCUTCHAN: One thing we should notice here is that

  • when we're looking for the summary of objects allocated

  • between snapshots one and two, you can tack on the sentence

  • that are still alive at snapshot three.

  • So from the moment in time that snapshot three was taken,

  • these are objects that were allocated between one and two

  • that are still alive.

  • So we should not see any stuff here, if we

  • weren't leaking memory.

  • LOREENA LEE: Correct, exactly.

  • So we are leaking memory.

  • And we do see that there are five objects that were

  • allocated between subjects one and two that are still alive

  • in snapshot three.

  • So if we go ahead and expand this, you can see here that

  • the stuff, we can click on one of these.

  • And on the bottom, you'll see the retaining path.

  • And it'll tell you that it's being retained by the object

  • data, which is in this HTML div element.

  • And this helps you figure out where you're going to go and

  • fix the problem.

  • So you can tell exactly where this is retained from who's

  • holding on to the handle from it.

  • JOHN MCCUTCHAN: So remember the retaining path is the path

  • from a garbage collector root to the variable

  • that's being held.

  • LOREENA LEE: So the other thing to note is, here, none

  • of these stuffs have a background

  • that is colored yellow.

  • And if we look at the Summary View with everything that's in

  • snapshot three, we can look at stuff.

  • And we should see that half of them are yellow and half of

  • them are not.

  • JOHN MCCUTCHAN: So why are they yellow?

  • LOREENA LEE: So the yellow background indicates that

  • there's a JavaScript handle on this object.

  • So there's a way to reach this object through the JavaScript.

  • And if it's not colored yellow, there's very likely

  • not to be a JavaScript handle, which means you're going to

  • have a hard time cleaning it up.

  • You've probably lost its reference to it.

  • It's still on the DOM tree, but you lost your JavaScript

  • reference to it.

  • JOHN MCCUTCHAN: So you could regain a reference to this by

  • walking the dog.

  • LOREENA LEE: By walking the--

  • right, so it's not like it was in the previous slides where

  • we showed you that they were true garbage that had zero

  • path to the root from the root.

  • So it does have a path from the root, but there's no way

  • to access it from JavaScript.

  • So this is why this is a JavaScript memory leak and not

  • necessarily a garbage collectible leak.

  • JOHN MCCUTCHAN: So the yellow indicates

  • that there is a path.

  • And white indicates that there is not.

  • LOREENA LEE: And not a JavaScript path.

  • And if it were true garbage like we had seen in the graphs

  • that John presented earlier, it would be with a red

  • background.

  • And those are things that are in the [INAUDIBLE]

  • DOM tree.

  • They cannot be reached from the root of the DOM node.

  • But they're being retained by something.

  • So a lot of times in those cases--

  • and there's some good examples of this on the dev website

  • that have them highlighted in red.

  • And those are things that are being retained for some reason

  • or another.

  • but.

  • They're not reachable from the root of the DOM tree.

  • And so in those cases, you should be able to open the

  • retaining path.

  • And you should see something highlighted in yellow, which

  • says you have a JavaScript reference to this thing.

  • But it's not in the DOM tree at all.

  • And that should help you.

  • JOHN MCCUTCHAN: So these are detached DOM nodes.

  • LOREENA LEE: Right.

  • And there's a great example of that online as well so that we

  • can go through that.

  • So I think that's pretty much the demo.

  • So we can recap it.

  • Let's go back to the slides and recap.

  • So we presented when Comparison

  • View just isn't enough.

  • And we showed that not all memory leaks result in

  • detached DOM tree nodes.

  • There are things like unintentional unbounded array

  • growths, so you add things to an array to

  • be processed later.

  • And you forget that you need to clean it up at some point.

  • So either you process it and you never dumped it.

  • So these kinds of things can be caught with this three

  • snapshot technique that I just presented.

  • And there's one other case.

  • That's lingering event handlers retaining DOM nodes

  • that are otherwise detached.

  • And that can be seen in the scenario that I just

  • explained, where you would have something in red with a

  • retaining path that has some yellow nodes in it.

  • And so that's when you would want to bring out your three

  • snapshot technique.

  • JOHN MCCUTCHAN: So these are some closure function that is

  • attached as an event list node to DOM node that

  • is out of the DOM.

  • LOREENA LEE: Correct.

  • And this is just a graphical representation of

  • what we just did.

  • But it's much better to see that in the dev tools

  • themselves.

  • So hopefully this was helpful.

  • JOHN MCCUTCHAN: Yeah, I think so.

  • I learned a lot.

  • LOREENA LEE: Sounds good.

  • JOHN MCCUTCHAN: So I think we have a little bit of time.

  • So here's a little quiz, the tale of the

  • missing object key.

  • So if we look at the source code on the slides here, you

  • see a new object is constructed.

  • It's empty.

  • A key called, double was added and assigned to double value.

  • A key called, integer was added and assigned an integer.

  • Then when you look at the object, you can see the key

  • double and integer are there.

  • And the two values are there.

  • So if you were to then take a heap snapshot and look at the

  • heap snapshot and find the object, o, inside the

  • containment view, you'll notice that the integer key is

  • missing from the heap snapshot.

  • That seems a little weird, because we just confirmed that

  • it is inside o, and it is in fact inside o.

  • But what's going on here is that v8 has some tricks in how

  • it stores integers.

  • If the number fits into a signed 31-bit integer, then

  • it's actually stitched into the object graph structure and

  • not actually part of the object graph, which is kind of

  • interesting.

  • So look out for that.

  • There's also cases where a property

  • is backed by a getter.

  • And so when you do a heap snapshot, the heap snapshot

  • can't call the getter because it might alter the program

  • state or might be incredibly expensive to call the getters,

  • because there could be many thousands of these objects

  • with these getters.

  • It avoids doing that.

  • So you might see when you take a heap snapshot that some keys

  • are missing.

  • But they're still there.

  • LOREENA LEE: Good things to be careful.

  • JOHN MCCUTCHAN: So thanks a lot for joining us, Loreena.

  • LOREENA LEE: No problem.

  • Thank you.

  • Thanks for having me.

  • JOHN MCCUTCHAN: Bye.

  • LOREENA LEE: Bye, everyone.

[MUSIC PLAYING]

Subtitles and vocabulary

Click the word to look it up Click the word to find further inforamtion about it