JavaScript Garbage Collection

JavaScript Garbage Collection and Your Web App Performance

This is how garbage collection works in JavaScript and what exactly you need to do in order to improve your application’s speed and performance.

The JS garbage collection is the process that’s responsible for clearing out unused objects from memory. While this is a necessary and good process, and it is highly optimized (and keeps being optimized all the time), it has performance implications. The process runs on the main thread, and hence has the potential, in some cases, to block the JavaScript Event Loop.

Main Takeaways

  • Garbage Collection (GC) is the process responsible for cleaning out the memory from unused objects.
  • The GC has a part running on the main thread, hence it has an effect on performance.
  • Various optimizations have been made to GC over the years – algorithmic, parallel, chunking and concurrency.
  • GC is triggered by the allocation of many objects until some memory threshold is reached.

How Garbage Collection Works in JavaScript

The JavaScript garbage collection works generally the same in the major browsers with minor differences. Here I’ll address mostly the V8 garbage collector (used in Node.js and chromium browsers) but the principles are mostly the same in other browsers (like Firefox ). Quick answer can be found in the article How does Garbage Collection work in JavaScript?

Your JavaScript applications create a lot of variables during their runtime. These variables are created and discarded a lot. Let’s look at one example:

socket.on('someEvent', (dataObject) => {
  if (!dataObject.needToDoSeomthing) return;
})

In the code example above, we have a listener that fires whenever a message for “someEvent” reaches the client. It then receives a dataObject. This dataObject is allocated a place in memory and it is used inside the function. When the function finishes to run, we do not need this object anymore and should not have it in memory. Now the garbage collector comes into play.

The GC starts to go over some known global root objects (like window in the browser). It then follows the properties path. For instance, we have:

window.someObject.someObjectChild.someObjectChildsChild

When the garbage collector finishes this run, it marks all the objects that have no path from the root for collection (e.g. removal from memory). This process happens periodically and allows us, JavaScript developers, to develop with almost no concern for memory allocation and cleanup.

How does Garbage Collection affect performance?

The garbage collection process has an overhead in our JavaScript’s main thread. This means that while GC is running, it blocks our event loop and no other code is able to run. Here’s an illustration of how it works:

Figure 1: Garbage collection blocks the main thread.

This is why optimizing garbage collection is a big project for the JavaScript engines’ developers.

What optimizations have been made to JavaScript Garbage Collection?

Because Garbage Collection is a process that happens a lot and blocks the main thread, many optimizations have been made to it over time.

The optimizations are divided into 4 categories:

  1. Algorithmic
  2. Parallel
  3. Incremental
  4. Concurrent

The algorithmic optimizations revolve around the garbage collection implementation details. Stuff like heuristics and other kinds of optimizations are being made. One very important and famous optimization is the generational algorithm.

The objects in memory are split into generations – Young and Old. Young are objects that did not yet go through a sweeping process while the Old are those who survived a garbage collection. The plot thickens, because the Young are split into two groups: Nursery and Intermediate. There are various optimizations done there, based on the hypothesis that Most objects die young. We saw that in the listener example above. This prevents copying objects to the Old Generation which is a costly process. Copying objects is costly because the engine needs to allocate memory for the copied objects and then defrag the memory after deleting the old objects.

The process that handles solely in Young Generation is called Minor GC. The process that handles the memory as a whole is called Major GC.

Parallel optimizations were made such that the calculations of the garbage collector are being shared by multiple threads. This helps to reduce the time it takes the Garbage Collector to work in the main thread. In the illustration below, you can see the Before top section showing all the GC being done on the Main Thread, while in the After bottom section you can see it is shared between threads.

There’s a small overhead of synchronizing between the threads, but the performance benefits of “load balancing” outweigh the costs.

Figure 2: Parallelization of the GC process. Top shows before parallelization and bottom illustrates how it works afterwards.

Incremental optimizations are focused on chunking the GC to small bits. This allows constant memory cleanup while keeping the GC chunks very short.

Figure 3: Illustration of the incremental optimization. GC instances are split into smaller chunks.

There are issues here as well. For instance, because we split the clean up to small chunks with JavaScript running in between, the code might change the known memory state and chunks will be irrelevant or not up-to-date. 

The engineers working on the JavaScript engines managed to overcome most of these problems and bring us this optimization for our benefit.

Concurrent optimizations are optimizations that revolve around running some of the Garbage Collection algorithm along the JavaScript code running in the main thread. We cannot really clear the memory while JavaScript is running, but we can start marking objects for removal.

All of these optimizations are already in your browser and help you create faster applications.

What triggers Garbage Collection in JS?

The GC is triggered in two main cases:

  1. When the Young Generation passes some memory threshold
  2. When the Old Generation goes over some heap size.

There are algorithms and heuristics involved that try to predict and optimize according to how the application is running. The thing is – the more memory you allocate and the faster you do it, the more collection processes will run.

Can we trigger garbage collection from our JavaScript code?

There’s no way to trigger the process manually. You could allocate and release a lot of objects and cause GC implicitly, but there’s no command like “document.collectGarbage”.

First, it’s not in any JavaScript spec. A second and more critical reason – many optimizations for garbage collection are based on it setting the rules and being able to predict and schedule GC cycles. By allowing users to meddle with this schedule, the optimizations will have a big unknown variable in the equation. 

Summary

Garbage collection is the process that eventually cleans up our memory. It goes over our objects from some root objects (like window in the browser) and marks objects that are not in any reference path as “marked for removal”. It eventually removes these objects from memory.

Objects have a generational classification. New objects are in the Young generation while objects that went through more than one garbage collection cycles are in the Old generation. This allows JavaScript to apply optimizations and defrag memory more efficiently.

The garbage collection affects your application’s performance because it always has a part that’s running on the main thread. Optimizing your code to create less garbage collection is desirable in Performance Critical areas of applications.


Once in a week I publish a FREE newsletter for developers and programmers who are interested in taking their skills to an expert level.

And I invite you to sign up right now. Just a few of my optimization techniques can make a big difference to the performance of your applications.


Sign Up for our FREE newsletter and get our best articles delivered to you by e-mail


What you will learn:

  • How to make simple changes to your code to achieve the HIGHEST JavaScript performance possible
  • An easy, effective way to TEST your code and find places to make improvements
  • Practical tips on how to improve JavaScript MEMORY performance and reduce garbage collection
  • An expert advice on JavaScript from the leading programmers in the field
  • JavaScript Performance hacks and shortcuts to save you time and boost efficiency

Enter your name and email to access your FREE membership

*** We take your privacy very seriously. We hate spam as much as you do, so rest assured that your contact details will never be shared with a third party.


JavaScript Performance Optimization Tips
Node.JS performance optimization

Easy ways to test and improve Node.js performance

Here’s how to measure Node.js code efficiency and significantly boost Node’s performance. Simple tips that will improve your Nodejs code CPU and memory consumption.

JavaScript Memory leaks

Here’s how to find and fix memory leaks in JavaScript

JavaScript memory leaks can be easily found and fixed when you know what and where to look for. To spot a memory leak you need to follow those easy steps.


Javascript JS performance optimization

Test and optimize JavaScript performance

Practical steps to help you find and eliminate JS performance problems. A step-by-step guide to fixing common JavaScript performance bottlenecks in Web Apps.