Skip to main content

Memory Management and Garbage Collection in Javascript

Garbage collection in JavaScript is a form of automatic memory management. The garbage collector attempts to reclaim memory occupied by objects that are no longer in use by the program. Here’s a brief overview of how it works in JavaScript.

Memory Management

In Javascript, Memory Management is handled automatically by the runtime environment.

Stack and Heap

Javascript uses two types of memory to store Objects:

  • Stack stores function calls and local variables, such as strings, numbers, booleans, etc.
  • Heap is used to store more complex data structures, such as objects and functions. Memory allocation and deallocation here are more complex than in a stack.
StackHeap
Primitive data types and valuesObjects, functions and arrays
Size is known at compile timeSize is known at run time
Allocated a fixed amount of memoryNo limits to the amount of memory

Memory Lifecycle

The process of memory management consists of three main stages:

  1. Allocate. Javascript automatically allocates memory when objects are created.
  2. Use. The program uses allocated memory only for reachable and necessary objects.
  3. Release. Once values are no longer needed or they become unreachable, the memory they occupy is marked for reclamation by the garbage collector.

Garbage Collection

JavaScript primarily uses two garbage collection strategies: Reference Counting and Mark and Sweep.

Reference Counting

This was an earlier method used in some JavaScript environments, such as some versions of Internet Explorer.

It tracks the number of references to each object. If the reference count drops to zero, the object is no longer needed and can be collected as garbage.

However, this method can lead to issues like circular references, where two or more objects are referenced in a loop, preventing their memory from being released.

Reference Cycling Problem

A cycling reference problem in JavaScript typically occurs when two or more objects reference each other, creating a cycle. This can lead to memory leaks because the garbage collector may not be able to reclaim the memory used by these objects if they're not explicitly nullified or disconnected.

Example of Reference Cycling

Let's consider two objects, parent and child, where parent has a reference to child and child has a reference back to parent.

let parent = {
name: "Parent",
child: null
};

let child = {
name: "Child",
parent: null
};

// Creating the cycle
parent.child = child;
child.parent = parent;

To prevent memory leaks caused by such cycles, it is important to break the cycle by setting the references to null when the objects are no longer needed:

// Breaking the cycle
parent.child = null;
child.parent = null;

// Now the garbage collector can reclaim the memory
// if there are no other references to `parent` and `child`

In modern JavaScript engines like V8 (used in Chrome and Node.js), there are advanced garbage collection techniques like mark-and-sweep that can identify and collect circular references.

Mark and Sweep Algorithm

The Mark and Sweep algorithm is crucial for managing memory in JavaScript. It efficiently identifies and cleans up unused objects, ensuring that applications run smoothly without unnecessary memory bloat or leaks.

Mark and Sweep Algorithm in JS

Algorithm

  1. Tracing reachable objects. The garbage collector starts by identifying "roots". Roots are generally variables and references directly accessible in the program, such as global variables, local variables in the stack, and references held in CPU registers.
  2. Marking. From these roots, the garbage collector traces all reachable objects. This involves recursively visiting all objects that can be accessed directly or indirectly from the roots. Each visited object is marked as "reachable," which prevents it from being collected as garbage.
  3. Identifying Garbage. After all reachable objects have been marked, the sweep phase begins. During this phase, the garbage collector scans the memory heap and identifies which objects have not been marked.
  4. Memory Reclamation. Unmarked objects are considered unreachable and, therefore, garbage. They are then collected, and their occupied memory is reclaimed. The reclaimed memory can then be used to allocate new objects.

Simplified implementation

let heap = {
"object1": { referencedBy: [], marked: false },
"object2": { referencedBy: ["object3"], marked: false },
"object3": { referencedBy: ["object1"], marked: false },
"object4": { referencedBy: [], marked: false } // Unreachable object
};

let roots = ["object1", "object3"]; // Root objects, typically global variables


const mark = (objectId) => {
let stack = [objectId];

while (stack.length > 0) {
let current = stack.pop();
if (!heap[current].marked) {
heap[current].marked = true;
heap[current].referencedBy.forEach(ref => {
stack.push(ref);
});
}
}
}

const sweep = () => {
Object.keys(heap).forEach(objectId => {
if (!heap[objectId].marked) {
console.log("Collecting " + objectId);
delete heap[objectId];
} else {
heap[objectId].marked = false; // Clear mark for next GC cycle
}
});
}

// Start marking from all root objects
roots.forEach(root => mark(root));

sweep();

Summary

  • Javascript uses two types of memories to store Objects: Stack and Heap
  • Memory management lifecycle consists of 3 stages: Allocate, Use and Release
  • There are two algorithms in Javascript which is used for Garbage Collection: Reference counting and Mark and Sweep. Mark and Sweep algorithm is primirily used in most of the browsers.

References