Brief introduction to Memory leaks and Garbage collector algorithms in JavaScript

Brief introduction to Memory leaks and Garbage collector algorithms in JavaScript

We developers often complain that JavaScript(JS) apps tend to issues regarding poor performance, severe slowdowns, frequent crashes or high latency and all our attempts to figure out the problem goes in vain. This is when there is a high chance of your code to have 'Memory Leaks'. We will understand about Memory leaks and what are garbage collectors. Memory Leaks are quite common as we developers neglect memory management often, and this is due to the misconceptions about automatic memory allocation and release. Failure to deal with memory leaks in JS can wreak havoc in the performance of your app and make it unusable.

So, what are JS Memory Leaks?

A Memory leak could be defined as a piece of memory that isn't used anymore or required by an application, but for some reason, it is not returned back to the OS and is occupied needlessly. Object and variable creation in code lead to memory consumption. JS is quite smart to understand when we don't need an object and it clears the memory in order to save memory. Thus, a memory leak occurs when we no longer need an object, but the JS runtime assumes that we need it. This is something which is not caused when code is invalid, but because of logical flaws in code. Performance of application gets reduced due to the reducing memory to perform tasks and this is for frequent crashes and freezes.

Something important concepts to know before getting into Garbage collectors are Memory cycles, Garbage Collector Algorithms and Memory Management Systems.

Let us understand Memory Cycle

A 'memory' is made of a series of flip-flops, which is a 2-state(0 & 1) circuit formed by 4 to 6 transistors. Once, a bit is stored in the transistor, it is retained until it is rewritten with the opposite bit. Hence, memory is just an array of reprogrammable bits. Every data used in a program is stored in the memory.

Memory Cycle is a cycle by which a unit of memory goes from an idle state to the usage phase or vice versa. Memory cycle is made of 3 steps:

  1. Memory Allocation
  2. Memory Usage
  3. Memory Release

Memory allocation: This memory is allocated by the OS to various programs during execution as per requirements. This is handled by the developer in low-level programming languages like C and C++, unlike JS. In JS, this is done by the automatic memory management system. Some examples of memory allocation in JS are as given below:

var var1 = 5; // allocates memory for a number
       var myString = "Hello GeekPoint"; // allocates memory for a string
       var obj1 = { // allocates memory for an object
           a1: 100,
           a2: "some string",
           a3 null,
       };
       var arrChar = [100, "some string", null]; // allocates memory for the array
       function doSomething(num1, num2) { // allocates memory for a function
           return num1*num2;
       }

Memory Usage: Programs carries out the read and write a function on the memory which is allocated. This can be reading or writing the value of a variable, an object or it can even be passing of an argument to a function.

Memory Release: When the task is completed and the allocated memory is not required anymore, then it is released and made free for the new allocation.

Now, all the complication happens in the Memory Release segment. Here, the problem lies in understanding when " the allocated memory is no longer needed and it should be made free". This is when Memory Management System and their Garbage Collector Algorithm comes into the picture.

Let's understand the difference between Memory Management System-Manual & Automatic Memory Management System

Memory Management is the process of assigning blocks of memory to different programs during execution at their request, and free it when not required and relocated. Different programming languages use different Memory Management Systems.

  1. Low-Level languages like C, Pascal, and C++ use a manual memory management system where the developer must manually allocate memory when required and then free it up after the use of the memory is over. For example, C and C++ use malloc() and calloc() to reserve memory, realloc() is used to move a reserved block of memory to any another allocation and free() was used to release memory back into the system.

  2. High-level programming languages like JS have an automated system that helps it to allocate memory each time we create an entity like- an object, an array, a string, or a DOM element and automatically frees it up when they are not used anymore. This is carried out by a process known as garbage collection.

Garbage collector

The process of finding memory which is no longer in use by the program and then release that memory back to the operating system is done by garbage collectors. Now, how do these garbage collectors work? Actually, working depend on the algorithms. And, I would agree with anyone who would say that these garbage collectors are amazing at their work, but sometimes, leaks do occur and most of the time, the cause for the leaks is-"Unwanted reference". And now, the next question would be, why the unwanted reference is the primary reason? Actually, the process of garbage collection depends on estimation, and for complicated problems, it becomes hard for the algorithm to determine whether the memory could be freed or not.

The 2 most widely used popular algorithms are as follows:

  1. Reference Count.
  2. Mark & Sweep algorithm.

Reference Count Algorithm

This is an algorithm that depends on 'reference'. It depends on the number of references are made to an object from other objects. With the creation of an object or when a reference to an object is assigned, the reference count gets increased. This could be considered as the most basic algorithm for garbage collection. It is based on this simple rule: One can consider an object for garbage collection and no longer to be used if there are no references pointing to it.

Let us understand this with a simple example.

var obj = {//We create 2 objects, One is referenced by the other as one of its properties.
a: {//the other is referenced by virtue of being assigned to the 'obj' variable.
b: 2;//Everything seems fine and none could be garbage collected.
}
};
var obj1 = obj;//the obj is the second thing which has the reference to the object.
obj1 = 1;//now, the object that was in obj is now in obj1
var obj_a = obj1.a;//reference to 'a' property of the object obj1, now this object has two references: One as a 'obj_a' one as a property
obj1 = 'GeekPoint';// the object that was originally in 'obj' now has no reference to it. Thus, it can be garbage collected.
//But..it is still referenced by obj_a. Thus, it cannot be freed.
obj_a = null;//the 'a' property of the object originally in obj has zero references in it. It can be garbage collected.
</script>

Drawback: There is one drawback in regard to cycles in the Reference count algorithm. In the case of cycles, the garbage collector algorithm does not collect them even when they are not in use.

       function instanceSomething() {
           var firstObj = {};
           var secondObject = {};
           firstObj.x = secondObject; // obj1 references obj2
           secondObject.x = firstObj; // obj2 references obj1

           return true;
       }
       instanceSomething();
</script>

Mark and Sweep Algorithm

Here in JS, any global object is known as 'root'. Here, the garbage collector first finds all the root objects in the code and will then map all references. Garbage collector first finds all root objects and then map all the references to these root objects and reference these objects and so on. With the use of this algorithm, the garbage collector finds all the reachable objects and garbage then collects all unreachable objects.

Mark and Sweep algorithm.jfif

This algorithm works in two phases:

  1. Mark Phase: When an object is created, the mark bit is set to false or 0. In this phase, whenever a is reachable, the mark bit is changed to 1. 2. Sweep Phase: All the objects where mark bit is still 0 (or false) after Mark phase is the unreachable objects and thus they are garbage collected and are freed from memory by the Mark and Sweep algorithm.

Advantages of Mark and Sweep algorithm Mark and Sweep engage with cycles. Any object which is unreachable from the root can be collected by the garbage collector.

Drawbacks of Mark-and-Sweep Algorithm The primary disadvantage of this algorithm is that when this is operational, the execution of the program is stopped or suspended.

Additional Resource

You can use Chrom Dev Tools to find memory leaks and to know more about it, do watch the following videos: Finding Memory leak using Chrome Dev Tools.