Garbage Collection - Memory Management in Javascript

ยท

5 min read

Introduction

Memory management in Javascript is a concept that is important to understand for the next few articles that I am going to upload on WeakMap and WeakSet.

Memory management in Javascript is something that happens automatically and remains invisible to us. The main concept of memory management in Javascript is "reachability". Everything that we create, be it objects, lists, functions, primitives, etc. occupies space in memory.

What is Reachability?

Anything that we create in Javascript, for eg: objects, lists, functions, primitives, etc., are called reachables and they occupy some space in memory.

Alright. The above explanation would be difficult to understand without understanding an example. Take a look at the code snippet below.

let user = {
  name: "Nikhil"
}; // user is a reference to the object.

user = null; // user is no longer a reference to the object as it is currently set to null.

In the above code snippet, I have created an object with the key - "name", and the value associated with it is "Nikhil" (which is my name by the way ๐Ÿ˜. Hello World!). This object is currently referenced by "user" and the object as of now is said to be reachable.

The moment I set the user to null, the object, which was previously referenced by user, is no longer referenced by user and hence has become unreachable.

Now, Javascript codes are called scripts and are executed by the underlying special program called the Javascript engine, which converts these scripts into machine code, and then the machine code is executed. More on the Javascript engine later in some other article, but a background process in the Javascript engine called the "garbage collection" monitors all objects and attempts to remove the ones from the memory that have become unreachable.

There are some reachables that can't be removed from the memory and are called roots. Examples of roots:

  • Currently executing functions, their local variables, and parameters.
  • Global variables
  • All functions in the current chain of nested calls, their local variables, and parameters.
  • Other values are called reachables if they can be accessed by the roots through some reference. For eg. an object containing a property which in itself is a reference to another object.

Interlinked Objects

Now, that we have understood the concept of reachability, let us look at another example to understand the concept better. Take a look at the code snippet below.

function marry(man, woman) {
  woman.husband = man;
  man.wife = woman;

  return {
    father: man,
    mother: woman
  };
};

let family = marry({
  name: "John"
}, {
  name: "Ann"
});

The above program looks something like this in the diagram.

1.jpeg

It is important to understand that in order to make a value unreachable, it is only important to ensure that all the incoming references to the values are removed. So for example, in the above diagram, let us say we want to make Object {name: "John"} unreachable. For that matter, we need to remove the incoming references to the object which are - "father", and "husband".

delete family.father;
delete family.mother.husband;

//remove the incoming references

Once the incoming references are removed, the resulting diagram looks something like this....

3.jpeg

The name of this garbage collector algorithm is "mark and sweep" and it removes the unreachables and preserves the reachables.

How does the "Mark and Sweep" work?

  • Starts from the root, and marks them as visited.
  • Visits and marks all the references from the root as visited.
  • Visits marked objects and marks their references. All visited objects are remembered, so as not to visit the same object twice in the future.
  • All unvisited objects are removed from the memory as they must be unreachable.

4.jpeg

During the garbage collection, the Javascript engine runs many optimizations to ensure lesser delays in code execution. Some of the optimizations are:

  • Generational Collection - Objects are divided into 2 sets: the old ones, and the the new ones. Some of the objects have a short life span, as in they do their jobs and die. So, it makes sense to keep track of the new objects and clear the memory from them. Those that last longer become "old", and are examined less often.

  • Incremental Collection - When there are many objects, trying to mark the whole object takes time, and introduces visible delays in code execution. So the engine splits the whole set into many parts together, and then clears these parts one after the other. There are many small garbage collections at work instead of a total one. This leads to tiny delays instead of the big ones and requires extra bookkeeping between them to track changes.

  • Idle-time Collection - The garbage collector tries to run only when the CPU is idle, to reduce the possible effect on the execution.

Final Thoughts

This topic was important for me to explain as the whole concept of the next two data structures - WeakMap and WeakSet which I am going to write about later, depends on the concept of reachability and so it was important for me to explain how memory management happens in Javascript.

With that, I want to leave you with some inspiration by quoting Steve Jobs. He said, and I quote, "Your work is going to fill a large part of your life and the only way to be truly satisfied is to do what you believe is great work and the only way to do great work is to love what you do. If you haven't found it yet, keep looking and don't settle. As with all matters of the heart, you will know when you find it and it gets better and better as the years roll by. So keep looking and don't settle".

You can follow me on Github, LinkedIn

ย