Node.js Memory Structure: V8 Memory Spaces Explained
Node.js relies on the Google V8 engine to manage memory, dividing its heap into distinct segments to optimize garbage collection and application performance. This article explains how Node.js structures its memory into specific spaces—including New Space, Old Space, and Large Object Space—and details how the V8 garbage collector manages objects across these segments to prevent memory leaks and ensure efficient execution.
The V8 Heap Memory Model
When a Node.js application runs, all dynamically allocated objects reside in the V8 heap. To optimize garbage collection (GC), V8 utilizes the “generational hypothesis,” which states that most objects die young. Consequently, the heap is split into several logical segments, each designed to handle objects at different stages of their lifecycle.
1. New Space (Young Generation)
The New Space is a small, highly active memory segment where almost all new objects are initially allocated.
- Characteristics: It is designed to be small—typically ranging from 1MB to 64MB—to ensure that garbage collection can happen extremely fast.
- Garbage Collection (Scavenger): The New Space is divided into two equal-sized semi-spaces: the To Space and the From Space. New allocations occur in the active semi-space. During garbage collection, the active objects are copied to the inactive semi-space, and the dead objects are discarded. The two spaces then swap roles.
- Promotion: If an object survives two consecutive scavenger garbage collection cycles, it is promoted to the Old Space.
2. Old Space (Old Generation)
The Old Space contains long-lived data that has survived multiple garbage collection passes in the New Space.
- Characteristics: This space is much larger than the
New Space and can grow up to the limit of the configured heap size
(controlled via flags like
--max-old-space-size). - Sub-segmentation: The Old Space is divided into two
distinct zones:
- Old Pointer Space: Contains survived objects that contain pointers to other objects.
- Old Data Space: Contains raw data payloads (such as strings, boxed numbers, and raw arrays) that do not point to other objects. This distinction prevents the garbage collector from wasting time scanning non-pointer data.
- Garbage Collection (Major GC): V8 uses the Mark-Sweep-Compact algorithm to clean the Old Space. Because this process is computationally expensive, it runs less frequently than the Scavenger algorithm.
3. Large Object Space
The Large Object Space is reserved for objects that exceed the allocation size limit of the New Space.
- Characteristics: When an object is too large to fit comfortably in standard memory pages (typically larger than 1MB), allocating and copying it during garbage collection would severely degrade performance.
- Management: Objects in the Large Object Space are allocated directly in their own dedicated memory pages. They are never moved or copied by the garbage collector; V8 simply deallocates the entire memory page when the object is no longer reachable.
4. Other Specialized Spaces
While the New, Old, and Large Object Spaces handle standard application data, V8 also maintains specialized spaces for system execution:
- Code Space: This space stores the actual machine code compiled by the V8 Just-In-Time (JIT) compiler. It is the only memory segment with execution permissions.
- Map Space (Cell Space): This contains “Shapes” or “Maps” of objects, which define the layout and property types of JavaScript objects to optimize property access.
- New Large Object Space: A dedicated area for large, newly created objects that cannot fit in the standard New Space but still need to be managed under the young generation rules before potentially transitioning to the main Large Object Space.