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.
Stack | Heap |
---|---|
Primitive data types and values | Objects, functions and arrays |
Size is known at compile time | Size is known at run time |
Allocated a fixed amount of memory | No limits to the amount of memory |
Memory Lifecycle
The process of memory management consists of three main stages:
Allocate
. Javascript automatically allocates memory when objects are created.Use
. The program uses allocated memory only for reachable and necessary objects.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.
Algorithm
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.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.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.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.