Garbage Collection in JavaScript: Explained in Simple WordsGarbage Collection in JavaScript: Explained in Simple Words

Garbage collection in JavaScript, or in any programming language that uses it, is like a magic piece of code that cleans up the memory your program no longer needs. This is especially important in languages like JavaScript, where developers do not manually allocate and free memory, unlike some other languages like C/C++. This is handled automatically in JavaScript by the JavaScript Engine (a software that executes JavaScript code, such as browsers). Let's break it down with a simple party example 🍷.

What is Garbage Collection

Imagine you're at a party, and guests are constantly arriving and leaving. Over time, some guests linger, not really participating, just taking up space. In computer terms, your program's memory is the party room, and the guests are various data objects your program creates. Garbage collection is the process of clearing out those "lingering guests" to make room for new ones, ensuring the party (your program) continues without a hitch. Chrome's Javascript engine (also called V8) uses a smart algorithm called "Mark and Sweep" to do this, which we'll discuss in a while.

How Websites Use Memory

When you visit a website, your browser loads the HTML, CSS, and JavaScript files that make up the page. As the JavaScript code runs, it creates variables, objects, and data structures that take up memory. For example, let's say you have a simple script that creates an array of numbers:

let numbers = [1, 2, 3, 4, 5];

This line of code allocates memory to store the array and its contents. Now imagine if this script kept creating new arrays without ever releasing the memory used by the old ones. Over time, the website would use up more and more memory, potentially slowing down or even crashing the browser.

Why Memory Cleaning is Needed

Memory cleaning, or garbage collection, is crucial for several reasons:

  • Limited Resources: Computers have a finite amount of memory. While modern devices come with substantial RAM, inefficient memory usage can still lead to problems, especially on devices with less memory or when many applications are running simultaneously.

  • Performance: Applications that use memory efficiently tend to run faster and more smoothly. Excessive memory usage can lead to longer load times, sluggish response to user input, and, in severe cases, browser crashes.

  • Leaks and Bloat: Without proper memory cleaning, a website can continue to consume more and more memory as it runs. This is known as a memory leak. Over time, even the most minor leaks can add up, causing significant performance degradation and a poor user experience.

Mark and Sweep algorithm

To prevent memory from overflowing, JavaScript engines use an automated garbage collection algorithm called "mark and sweep". Here's how it works:

  • The garbage collector starts by identifying all the "roots" - variables and objects that are directly referenced by the program.
  • It then follows the references from these roots to other objects, marking each one as it goes. This is called the "mark" phase. Think of it as going through the room (memory) and putting a sticker on all guests (data objects) who are actively participating or are connected to the main group. It starts with the most obvious participants (root objects) and then marks anyone they are directly interacting with. This marking continues, creating a chain of active participants.
  • Once all reachable objects have been marked, the garbage collector (GC) begins the "sweep" phase. It scans through the memory and frees up any objects that were not marked. In our party example, think of it as, after everyone who should be at the party is marked, the sweep phase begins. Now, it's time to gently guide those without stickers (unmarked data objects) to the exit, clearing up space in the room. These unmarked objects are considered "garbage" and are removed from memory.

Let's understand these with a code snippet.

Please note that this is a representation of the algorithm and not the actual code used in the V8 engine. The actual implementation is much more complex and optimized for performance.

// Function to simulate the "Mark" phase of garbage collection using DFS
function mark(root) {
    if (root === null || root.isMarked) {
        return; // If the object is null or already marked, stop the traversal
    }
    root.isMarked = true; // Mark the current object as reachable
    for (let key in root) {
        if (typeof root[key] === 'object') {
            mark(root[key]); // Recursively mark reachable objects
        }
    }
}
// Function to simulate the "Sweep" phase
function sweep(objects) {
    // Filter out null objects and unmarked (and thus unreachable) objects
    return objects.filter((obj) => obj !== null && obj.isMarked);
}

The code provided is a basic version of the mark-and-sweep garbage collection algorithm. It marks reachable objects through a depth-first search with the mark function and then removes unmarked objects using the sweep function, which scans a collection of objects for those without the isMarked property.

The "Sweep" phase differs from "Mark" in that it doesn't traverse the object graph but simply scans the heap (or a collection of objects, in this case), collecting or filtering out objects deemed unreachable, based on their marked status.

Now, let us imagine a piece of JavaScript code on our browser and see how the mark and sweep algorithm would work in a real scenario.

// Example code
let person = {
    name: 'John',
    age: 30
};

let job = {
    title: 'Developer',
    company: 'Acme Inc.'
};

// Link person to job
person.job = job;

// Simulate removing the reference to 'person'
person = null;

// Start marking from the root (assuming 'job' is a root object)
mark(job);

// Assuming we have an array of all objects in our environment. In a real scenario, the Garbage Collector (GC) would have access to all objects in the heap.
let allObjects = [person, job];

// Simulate garbage collection
let objectsAfterGC = sweep(allObjects);

// Assuming 'person' is not reachable anymore and would be collected by GC in a real scenario
console.log(objectsAfterGC); // This should only include 'job' as it is still reachable

Code Explanation

Under the hood, the garbage collector uses a depth-first search (DFS) algorithm to traverse the object graph and mark reachable objects. DFS is a common graph traversal algorithm that explores as far as possible along each branch before backtracking.

In the above code, we start with two objects, person and job, which are both reachable from the root. We then set person's job property to reference the job object. Finally, we set person to null, meaning it is no longer reachable. At this point, the garbage collector will mark person as eligible for collection, but job will remain since it is still reachable.

All this is handled automatically by the JavaScript engine.

Note: Feel free to copy and paste the code snippets into your browser's console to see the results for yourself.

Further Optimizations in Chrome V8 Engine

On top of this, the V8 engine employs a clever strategy known as generational collection, based on the observation that most objects die young. It segregates objects into two generations: young (new space) and old (old space). New objects are allocated in a special area and are subject to more frequent cleanups. If they survive these early cleanups, they "move" to the old generation, where they enjoy a longer, more stable existence. This strategy is like having a VIP section at the party for guests who stick around longer, thus making the cleaning process more focused and efficient. Refer to the future readings below to learn more about garbage collection in V8.

Incremental Marking and Lazy Sweeping

To avoid disrupting the program too much, V8 also introduces incremental marking and lazy sweeping. Incremental marking is like cleaning up in small intervals throughout the party, rather than waiting until the end. Lazy sweeping takes this a step further by delaying the cleanup until the space is actually needed, reducing the workload and keeping the party going without noticeable interruptions.

Future readings

Conclusion

Understanding the "Mark and Sweep" garbage collection process in JavaScript, especially within the V8 engine, unveils the intricate yet essential mechanisms that keep our browsers running efficiently.

So, the next time your web application runs smoothly, remember the unsung hero behind the scenes: the garbage collector, diligently working to ensure a seamless experience.


If this article helped you, consider it sharing with your friends and colleagues. If you have any questions or feedback, feel free to comment down below. Happy coding! 🚀

Comments