Test Your JavaScript Knowledge

Garbage Collection

Lydia Hallie

Lydia Hallie

Lydia Hallie
Test Your JavaScript Knowledge

Check out a free preview of the full Test Your JavaScript Knowledge course

The "Garbage Collection" Lesson is part of the full, Test Your JavaScript Knowledge course featured in this preview video. Here's what you'd learn in this lesson:

Lydia discusses various concepts related to garbage collection in JavaScript. They explain how objects are garbage collected based on their availability in the global lexical environment and how references to objects affect their garbage collection. The instructor also explains the concept of weak maps and how they differ from regular maps in terms of garbage collection. They also discuss closures and when inner functions become eligible for garbage collection. The lesson concludes with a discussion on the event loop and how it interacts with garbage collection.


Transcript from the "Garbage Collection" Lesson

>> That was all on iterators and generators. We go to garbage collection, also fun. So one important thing about garbage collection is that, all depends on the availability from the global lexical environment. So here we have that object, our object that then points to the object in memory with age and johndoe and then address is another object which is another object in memory.

Now, if we set a variable equal to the address property on object, we're actually just creating a reference to that object in memory. So now if we set object to null, it will remove that reference from the declarative environment record. But because it address still has a pointer to that object, that address used to point to it, that won't get garbage collected cuz it's still reachable from the global lexical environment.

Now, we can also have them point to each other. So we have objA and objB and their properties both point to each other. But now if we set objA and objB to null, objA and objB are kind of still there and they still reference each other, but they aren't referenceable anymore from the global lexical environment.

And this is a pretty recent thing cuz older JavaScript engines now used to say, okay, well, there is still a reference though to objB and to objA, namely through objA and objB. But the newer ones say, if they aren't reachable from the global lexical environment, then we garbage collect them.

Even though there was still a reference, that's fine, but if we cannot reach them ever, then why keep them? But that's only well, a newer garbage collection method. Yeah, anyway, that's all the garbage collection really is. But now question 25, which of the following statements are true about a WeakMap?

Keys are strongly referenced and the values are weakly referenced. Keys are weakly referenced and the values are strongly referenced. It is innumerable, allowing iteration over its elements. It can have primitive data types as keys, and we can use the key method on the WeakMap, but not values. The right answer, is only B, which is keys are weakly referenced and the values are strongly referenced.

So first, I just wanna show a quick example with a regular map, so not a WeakMap. And in this case, we have you user, which is just a regular object with a name property, johndoe. And then userSessionata, which is a Map. And we're setting the key to user, so a reference to that object.

And then we just have some sessionInfo, so just imagine that's another object with some information. Now, what happens is that if we set user to null also, there's no reference anymore from the global lexical environment to that or we're just having that to null there. Because map still has a strong reference to that object, it doesn't get garbage collected.

But there is no way to get that object. So it's kind of just a waste of having that object there, cuz there's no way to get it. We cannot get that user object through userSessionData. So what WeakMap does is it actually creates a weak reference, which essentially says that, if we set user to null, because it's a weak reference, the garbage collector can actually garbage collect it, which is just that's all that WeakMap is.

So if the object that we're using as a key doesn't exist anymore or we're setting it to null, then it also gets garbage collected on the WeakMap. Even though it kinda still had a reference from the global lexical environment through like the userSessionData map, but it's like a weak reference, so it gets garbage collected.

Yeah, yeah, sorry.
>> What does it mean for the value to be strongly referenced there?
>> So it just means if we remove them sessionInfo, it's fine. It won't do anything with map entry kind of. But again, it's just about, cuz you can only get data from a map by using userSessionData.get, and then with the reference to that object.

But if we're setting it to null, there is no way to get that object anymore. You cannot get a property from the map through its value, only through its key. So that's why it's important that if you're using objects that can be removed, I don't know, maybe DOM elements.

Or yeah, a userSession and a user logs out and you're somehow have that user reference, maybe on the global scope or in local storage if they log out that you don't keep reference to that user property in the map. But yeah, for value doesn't matter cuz you cannot get the property through that anyway.

Yeah, Anyway, next, sorry. The next question, so we have another closure, but when will enter a function be eligible for garbage collection? Is it by invoking outer function? Is it by explicitly setting outer function to null? Is it automatically garbage collected right after outer is called? Or it depends on the JavaScript engine's garbage collection strategy.

So the right answer is B, by explicitly setting outer function to null. So this is kind of the setup that we have here. So we have an outer function on the object environment record that points to the outer function object. Then we have an outer function variable, declarative const, so it's on the declarative environment record.

And that one points to the function object returned from the outer function. So by just calling outer, there's still a reference to the inner function object, so it won't get garbage collected cuz it's still referenceable through the global lexical environment. So it's only if we set it to null, imagine we set it to null, that we remove that reference from outer function from the declarative environment record, and only then will it be garbage collected.

So it's just kind of the entire closure environment, again, where we have a reference to the function object which then also has a reference to either lexical environment and the outer function object. So it's all still there in memory if we just kept it this way. Make sense?

Cool, then we go on to the next question. Which statements are true regarding this code snippet? The object b:1 will be garbage collected, ref still references b:1 so it won't be garbage collected. The entire object object is retained in memory due to the reference in ref, or setting object to null frees all memory associated with it.

So the right answer is B, still references b:1. So it won't be garbage collected. So this is, stuff that we have, so we have objects and we have ref. And ref reference is B, objA. So whenever we set object to null, that's fine, that gets removed. But because we still have a reference to b from the global lexical environment, it won't get garbage collected, cuz we can still get it.

So, B.
>> That means if we were to console log graph, it would still-
>> It will point to b:1. But of course not, the object with a that had b:1 as a reference, that's gone. But the B object is still there. All right, question 8, it's again, WeakMap.

You can get a list of all keys in a WeakMap using its keys where you cannot get its values. I feel like this is like a duplicate kind of stuff I just have but it's fine. So it's a true false. All right, and the answer here is false.

I don't know if I have, yeah, so the thing with, sorry, this should have been WeakMap not map. The thing with the fact that it's keys are weakly referenced is that JavaScript doesn't know if they still exist cuz the garbage collection cycles are kind of random. It depends on different factors when it happens it's not just at a set time.

It's not after a function invocation, that garbage collection happens, it's just kind of whenever the engine decides that right now is the right moment. So if we were to iterate over a WeakMap, it might as well be that during that iteration, it gets garbage collected or it's just very inconsistent.

So because of that, we cannot iterate or pretty much do anything with a WeakMap. Because maybe at the moment of iteration is already garbage collected, all that kind of stuff. So we can get data, we can get userSessionData.getUser, that's fine. But we cannot get keys or values, even though values are strongly referenced, but we cannot do that.

We can do that with a map, but not with a WeakMap due to the inconsistency of the availability of the keys. All right, this one's kind of related to scope and garbage collection. But when will a user be eligible for garbage collection? Is it immediately after each iteration, after the loop completes?

Only if we explicitly set a user to null within a loop?. Or when the function containing the loop finishes execution. And the right answer is A, immediately after each iteration. So as I said, this is kinda just related to scope again, but that body of the for-of loop, it creates a new lexical environment on every iteration.

So the variables that we defined within that body get re-initialized every time. It's important to remember that it's only eligible for garbage collection, doesn't mean that they're immediately garbage collected, as I just said, cuz the timing at which that happens is random depends on many different factors when it's the most optimal for the engine.

That's just some internal algorithms, so I don't know the specifics off, but it's just pretty inconsistent. But yeah, within a for loop, variables declared within that can get garbage collected on every iteration. So don't create a constant count variable and then it, I don't know, use that value on the next iteration, that won't work cuz it's a new variable each time, new lexical environment.

So this one is kind of both the event loop and garbage collection, but what gets logged? So we have the object, object that has a bar method with console(this). We have a setTimeout that invokes object.bar, and then we have to queueMicrotask that deletes object.bar. So what gets logged, is an object, window, setTimeout, undefined, or TypeError?

All right, the right answer to this one is a TypeError. And this happens because we are deleting object.bar in the queueMicrotask. And as you know, the microtask runs before the regular task that we define in the setTimeout callback. So first we delete object.bar, and then when that microtask queue is empty, the callback.

So object.bar gets push to the call stack, but we are trying to invoke something that doesn't exist anymore cuz we just deleted that in the microtask. So then JavaScript is, well, you cannot invoke undefined, it's not a function. So it throws the type error
>> How much are you thinking about garbage collection, day to day work?

>> Quite a lot. I mean, it depends on how you structure your objects and how you reference certain things. And I think it also depends on classes, as we just said, with the prototypes or the constructors. Of course, it depends on the type of data you're working with, but it can be a considerate or a considerable difference in how much memory you're allocating.

And yeah, also the fact that certain things are pretty inconsistent, you don't know when stuff gets garbage collected, is just something to keep in mind as well. Cuz I think a lot of people, they expect all right, well I'm setting this to null now so it should be gone, and then it's not, so just knowing that it doesn't depend on certain factors.

Or it does depend on certain factors, but it doesn't always execute at the same time. It's also just good to know in case your app is running into memory issues in general. But it is important to know just how it works and how we can optimize it using QuickMaps, ensuring that we aren't just referencing objects that we aren't using anymore for no reason.

Yeah, and just understanding that if you are creating a reference, it will retain that in memory. And if you're not using anymore, then try to remove that reference. I don't know, small stuff like that. Just don't keep stuff in the heap for no reason or in memory for no reason.

>> That example for line number 10, if that line, [COUGH] if that line is object or bar equal null, it will have the same error type error, correct?
>> Yes, because we cannot invoke null. [LAUGH]
>> It will just garbage collected in that moment. Yeah, we said object.

>> JavaScript runs at line 10.
>> Yeah.
>> It's gone.
>> Exactly, cuz then object.bar is undefined cuz it's nothing. And then we're trying to invoke undefined. It's like, can't do that.
>> Do you use queueMicroTask instead of something like request animation frame or different use or?
>> It's a different use case cuz I believe request animation frame depends on, it he 16 frames per second?

Loop it uses a different like timing for that? You microtasks, yeah, I haven't used you or queueMicrotasks I think anytime. But I know that it's more for optimization for, gosh, library authors that depend watching the animations or, gosh, I forgot the word, but, yeah.
>> How do you think about garbage collection if you're creating a game in JavaScript?

>> Creating games? I haven't created a game in, [LAUGH] JavaScript, so I wouldn't know. But I think, of course, anything you render, if it's an object, if it's not currently in the view, you might as well just remove it. But again, I'm not the one to talk about that.

I know there are a lot of game developers with JavaScript, but I don't think I should give my opinion on [LAUGH] that. But, I don't know, do, yeah.
>> Yeah, I think in the case of single-page apps, they tend to just create a lot of objects, and there's a lot of dependencies.

And so I think, Yeah, just creating less memory.
>> Yeah, just like reusing it. If you have an object, the same with knowing that, if you're using an object and you're spreading it, like a square bracket is spreading an object, you're creating a new object, do you always need to do that?

Or maybe you just want to create a variable that points to the same object if you're not gonna modify, just understanding the small differences again, it kind of accumulates, right? As your app grows, those small changes might lead to better performance overall but-
>> Yeah, every time you spread, you create a new object and you're just if you're doing spreading in a loop, and you're doing it because you like immutability-

>> Yeah.
>> That's not really a great reason-
>> Yeah, really-
>> That much.
>> Knowing where to define certain variables if you only use it in a loop, just keep it in that loop. Cuz then afterward, it can get garbage collected, otherwise, it will just stay in memory.

And of course, on a smaller scale also JavaScript engines are so optimize. I don't really care about those micro optimizations about tiny, tiny bits. But as I said, it can accumulate and just knowing where certain errors may come from, certain performance issues may come from, it can definitely help you debug or get to the conclusion a lot faster.

Learn Straight from the Experts Who Shape the Modern Web

  • In-depth Courses
  • Industry Leading Experts
  • Learning Paths
  • Live Interactive Workshops
Get Unlimited Access Now