DEV Community

Cover image for Experiments with the JavaScript Garbage Collector

Experiments with the JavaScript Garbage Collector

Alexey Lebedev on February 23, 2023

Memory leaks in web applications are widespread and notoriously difficult to debug. If we want to avoid them, it helps to understand how the garbag...
Collapse
 
mindplay profile image
Rasmus Schultz

Thanks for this, very good article! 👍

I want to use the FinalizationRegistry in a test suite for a library that manages a bidirectional graph - I want to verify that nodes in the graph get correctly detached and become available for garbage collection, so as not to leave behind references that point to unused partitions of the graph.

Basically, I'd like to have something like await garbageCollectionOf(node) at the end of a test - do you know if it's possible to create a Promise that would resolve when an object gets garbage collected?

I tried, but this doesn't work:

function promiseAfterGC(obj) {
  return new Promise((resolve) => {
    const registry = new FinalizationRegistry(() => {
      resolve();
    });
    registry.register(obj, null);
  });
}

let obj = {};
promiseAfterGC(obj).then(() => {
  console.log("Object has been garbage collected");
});

// Remove reference to obj
obj = null;
Enter fullscreen mode Exit fullscreen mode

I tried Chrome and node (version 22) and deno (latest) and they don't print anything.

It's also worth noting that Node and Deno don't invoke finalization before they exit - I tried several of your examples, and they don't work in Node or Deno.

I was able to force garbage collection in Node, if I run node with the --expose-gc flag and then call global.gc(), it does collect garbage. If not, it never seems to invoke any finalizers - even a 10 second loop in a timer, where I allocated 64K of RAM every 50 msec, never printed anything to the console.

I think sever environments are much more unpredictable when it comes to BC scheduling - in the browser, I can trigger it by resizing the window, but in Node or Deno, only global.gc() seems to do it.

It makes me wonder what the intended use of finalization is? If it's not reliably going to get called, and it can't be combined with a test framework to test for memory leaks, what is the usefulness? What can you do with this? 🤷‍♂️

Collapse
 
sonsurim profile image
Sonny

Hi! I'm Surim Son, a front-end developer At Korean FE Article Team.
It was a very good article and it was very helpful.
I am going to translate the article into Korean and post it on Korean FE Article mailing substack(kofearticle.substack.com/), is it okay?
Korean FE Article is an activity that picks good FE articles every week, translates them into Korean, and shares them.
It is not used commercially, and the source must be identified.
Please think about it and reply. I'll wait! 

Collapse
 
alisey profile image
Alexey Lebedev Codux

Hi Surim. Sure, you're welcome to translate it.

Collapse
 
ianbromwich profile image
Ian B

Really interesting and well explained read. Thank you!