How Does Garbage Collection Work in JavaScript

When and How JavaScript garbage collector works

V8 developer here. The short answer is: it's complicated. In particular, different JavaScript engines, and different versions of the same engine, will do things differently.

To address your specific questions:

a) When does Garbage collector kicks in ( it gets called after some interval or some conditions have to met) ?

Depends. Probably both. Modern garbage collectors often are generational: they have a relatively small "young generation", which gets collected whenever it is full. Additionally they have a much larger "old generation", where they typically do their work in many small steps, so as to never interrupt execution for too long. One common way to trigger such a small step is when N bytes (or objects) have been allocated since the last step. Another way, especially in modern tabbed browsers, is to trigger GC activity when a tab is inactive or in the background. There may well be additional triggers beyond these two.

b) Who is responsible for Garbage collection ( it's part of JavaScript engine or browser/Node ) ?

The garbage collector is part of the JavaScript engine. That said, it must have certain interactions with the respective embedder to deal with embedder-managed objects (e.g. DOM nodes) whose lifetime is tied to JavaScript objects in one way or another.

c) runs on main thread or separate thread ?

Depends. In a modern implementation, typically both: some work happens in the background (in one or more threads), some steps are more efficient to do on the main thread.

d) which one of the following have higher peak memory usage ?

These two snippets will (probably) have the same peak memory usage: neither of them ever lets objects allocated by more than one iteration be reachable at the same time.


Edit: if you want to read more about recent GC-related work that V8 has been doing, you can find a series of blog posts here: https://v8.dev/blog/tags/memory

What is JavaScript garbage collection?

Eric Lippert wrote a detailed blog post about this subject a while back (additionally comparing it to VBScript). More accurately, he wrote about JScript, which is Microsoft's own implementation of ECMAScript, although very similar to JavaScript. I would imagine that you can assume the vast majority of behaviour would be the same for the JavaScript engine of Internet Explorer. Of course, the implementation will vary from browser to browser, though I suspect you could take a number of the common principles and apply them to other browsers.

Quoted from that page:

JScript uses a nongenerational
mark-and-sweep garbage collector. It
works like this:

  • Every variable which is "in scope"
    is called a "scavenger". A scavenger
    may refer to a number, an object, a
    string, whatever. We maintain a list
    of scavengers -- variables are moved
    on to the scav list when they come
    into scope and off the scav list when
    they go out of scope.

  • Every now and then the garbage
    collector runs. First it puts a
    "mark" on every object, variable,
    string, etc – all the memory tracked
    by the GC. (JScript uses the VARIANT
    data structure internally and there
    are plenty of extra unused bits in
    that structure, so we just set one of
    them.)

  • Second, it clears the mark on the
    scavengers and the transitive closure
    of scavenger references. So if a
    scavenger object references a
    nonscavenger object then we clear the
    bits on the nonscavenger, and on
    everything that it refers to. (I am
    using the word "closure" in a
    different sense than in my earlier
    post.)

  • At this point we know that all the
    memory still marked is allocated
    memory which cannot be reached by any
    path from any in-scope variable. All
    of those objects are instructed to
    tear themselves down, which destroys
    any circular references.

The main purpose of garbage collection is to allow the programmer not to worry about memory management of the objects they create and use, though of course there's no avoiding it sometimes - it is always beneficial to have at least a rough idea of how garbage collection works.

Historical note: an earlier revision of the answer had an incorrect reference to the delete operator. In JavaScript the delete operator removes a property from an object, and is wholly different to delete in C/C++.

Ensuring object can be garbage collected

Javascript uses a nongenerational mark-and-sweep garbage collector, in javascript objects are automatically garbage collected when they are no longer needed , so you need not worry about garbage collection.

but you have to keep these points in mind (from this answer):

  1. what you are trying with delete does not really delete an object, delete is only effective on an object's properties. It has no effect on variable or function names., Use delete statements whenever you create an object using a new statement, pair it with a delete statement. This ensures that all of the memory associated with the object, including its property name, is available for garbage collection. The delete statement is discussed more in “Freeing Objects.”

  2. Use the var keyword. Any variable created without the var keyword is created at the global scope and is never eligible for garbage collection, presenting the opportunity for a memory leak.

  3. In case of global variables, Global variables are never disposed of by the GC in the sense that a global variable will always exist. Setting it to null will allow the memory that it references to be collected. the memory used by the object will be eligible for collection. but The variable still exists though, and it simply references null(some more here)

Javascript and Garbage collection

Javascript doesn't have explicit memory management, it's the browser which decides when to clean it up. Sometimes it may happen that you experience un-smooth rendering of JavaScript due to a garbage collection pause.

There are many techniques that you can apply to overcome glitches caused by garbage collection (GC). More you apply more you explore. Suppose you have a game written in JavaScript , and every second you are creating a new object then its obvious that at after certain amount of time GC will occur to make further space for your application.

For real time application like games, which requires lot of space the simplest thing you can do is to reuse the same memory. It depends on you how you structure your code. If it generates lots of garbage then it might give choppy experience.

By using simple procedures: This is well know that new keyword indicates allocation. Wherever possible you can try to reuse the same object by each time by adding or modifying properties. This is also called recycling of object

In case of Arrays, assigning [] is often used to clear array, but you should keep in mind that it also creates a new array and garbages the old one. To reuse the same block you should use arr.length = 0 This has the same effect but it reuses the same array object instead of creating new one.

In case of functions: Sometimes our program needed to call a specific function more time or on certain intervals by using setInterval or setTimeout.

ex: setTimeout(function() { doSomething() }, 10);

You can optimize the above code by assigning the function to a permanent variable rather than spawning each time at regular intervals.

    ex : var myfunc = function() { doSomething() }
setTimeout(myfunc, 10);

Other possible thing is that, the array slice() method returns a new array (based on a range in the original array,that can remain untouched), string's substr also returns a new string (based on a range of characters in the original string, that can remain untouched), and so on. Calling these functions creates garbage if not reutilized properly.

To avoid garbage completely in JavaScript is very difficult, you could say impossible. Its depends, how you reuse the objects and variables to avoid garbage. If your code is well structured and optimized you can minimize the overhead.

Why does Node.js Garbage Collector not collect complied code of new Function()?

Generally, the garbage collector can and does collect compiled code, just like everything else.

Keep in mind that garbage collected systems don't free memory immediately when an object goes out of scope. At some point, the garbage collector will run again, identify unreachable objects, and free their memory.

In this particular case, it looks like DevTools are keeping extra data around (presumably for debugging purposes), which does make this look like a memory leak -- but only while DevTools are open. I've filed crbug.com/1141613 so the team can take a look.

How does garbage collection work in JavaScript?

How does garbage collection work?

The short answer is: When a block of memory (an object, say) is no longer reachable, it is eligible to be reclaimed. When, how, or whether it is reclaimed is entirely up to the implementation, and different implementations do it differently. But at a language level, it's automatic.

For example:

function foo() {
var bar;

bar = new ReallyMassiveObject();
bar.someCall();
}

When foo returns, the object bar points to is automatically available for garbage collection because there is nothing left that has a reference to it.

Contrast with:

function foo() {
var bar;

bar = new ReallyMassiveObject();
bar.someCall();
return bar;
}
// elsewhere
var b = foo();

...now a reference to the object survives the call, and persists until/unless the caller assigns something else to b or b goes out of scope.

Also contrast with:

function foo() {
var bar;

bar = new ReallyMassiveObject();
bar.someCall();
setTimeout(function() {
alert("Three seconds have passed");
}, 3000);
}

Here, even after foo returns, the timer mechanism has a reference to the timer callback, and the timer callback — a closure — has a reference to the context where it was created, which in turn contains the bar variable. As a result, in theory, what bar refers to isn't available for garbage collection immediately when foo returns. Instead, it's kept around until the timer fires and releases its reference to the callback, making the callback and the context it refers to eligible for GC. (In practice, modern JavaScript engines can and do optimize closures where they can. For instance, in the above, static analysis shows the callback doesn't refer to bar, and doesn't contain any eval or new Function code that might refer to it dynamically at runtime, so the JavaScript engine can safely leave bar out of the context the function refers to, thus making what it refers to eligible for GC — and modern ones do). (More about closures in this article.)

JavaScript has no problem handling cleaning up circular references, btw, so for instance:

function foo() {
var a, b;

a = {};
b = {};
b.refa = a;
a.refb = b;
}

When foo returns, the fact that a is referring to b and vice-versa isn't a problem. Since nothing else refers to either of them, they can both get cleaned up. On IE, this is not true if one of the objects is a host-provided object (such as a DOM element or something created via new ActiveXObject) instead of a JavaScript object. (So for instance, if you put a JavaScript object reference on a DOM element and the JavaScript object refers back to the DOM element, they keep each other in memory even when no one is referencing either of them.) But that's an IE bugissue, not a JavaScript thing.

Re:

is it because the vbscript GC is bad that people reverted to javascript as their standard client side api?

JavaScript was the original client-side web scripting language. VBScript only came later, when Microsoft came out with a browser, and was only ever supported in Microsoft browsers. JavaScript was and is the only client-side scripting game in town if you want to work with the broadest range of browsers. <subjective>It's also about eight times the language classic VBScript ever was. ;-) </subjective>

When is this scope/closure being garbage collected in javaScript?

Very briefly, garbage collection is a background process of the Javascript interpreter / virtual machine that automatically frees the memory of objects no longer needed by your program.

For example, since you think of it for event listeners: when you remove an event listener (a function usually) from some event dispatcher, it is likely that no other part of the program will have a reference to the event listener. Therefore, the garbage collector can and will (at some unknown time) free the memory that was taken by the event listener.

Since a closure references a scope object, in order to garbage-collect a closure it needs not only be unreferenced, but also the scope.

If I modify a bit your example:

/* some stuff ... */
function add10(a) {
var adder = function (x) {
return function(y) {
return x + y;
}
}

var sum = adder(10); //creates a closure
return sum(a);
}

var thirty = add10(20);

/* Some more stuff ... */

After add10 is called, even though the program continues to execute some more stuff, the garbage collector can free the memory associated to the closure sum, because it is no longer referenced, nor is the scope associated to it.

Whereas in this example:

/* some stuff ... */
function add10AndGet20Adder(a) {
var adders = function (x, y) {
return [function(z) {
return x + z;
}, function(z) {
return y + z;
}]
}

var sums = adders(10, 20); //creates a closure
return [sums[0](a), sums[1]];
}

var result = add10AndGet20Adder(50);
var sixty = result[0];
var add20 = result[1];

/* Some more stuff ... */

When executing some more stuff, sums[0] is no longer referenced, BUT add20 (sums[1]) still has a reference to the scope that references x andy, therefore none of the two closures in sums can be freed by the garbage collector, until add20 is referenced by the program.

I hope this makes it clearer, even though the examples are of course nowhere close to real code. In practice, you need to worry about this only if you develop a long-lived program (such as a single page application or nodeJS server) with complicated usage of closures. Otherwise, the memory usage of the closures is unlikely to be a problem.

This SO question gives more details about Javascript garbage collection: What is JavaScript garbage collection?

Do DOM objects get garbage collected in javascript?

If the elements haven't been inserted into the DOM and no other references exist, then yes they will be garbage collected, just like any other variables.

Modern browsers use a Mark-and-sweep algorithm for garbage collection, this means the garbage collector will look for and garbage collect objects that are unreachable. If you create elements in your function, but don't assign a reference elsewhere or don't insert them into the DOM, then they will be eligible for garbage collection after the function completes.

There is no need to manually try to free memory in JavaScript, it is all handled implicitly.

  • MDN documentation for Memory Management in JavaScript.


Related Topics



Leave a reply



Submit