Memory Management and Control
V8 Memory Model
The V8 engine divides memory into two main categories: heap memory and non-heap memory.
- Heap Memory: Primarily used to store JavaScript objects and arrays. Heap memory is automatically managed by V8 using garbage collection to reclaim memory occupied by unused objects.
- Non-Heap Memory: Includes code cache, string tables, compiled code, etc. This memory is controlled by V8 but is not subject to garbage collection.
Garbage Collection Mechanism
V8 employs multiple garbage collection algorithms, including Mark-Sweep, Incremental Marking, Concurrent Marking, and Generational Garbage Collection.
- Mark-Sweep: Traverses all reachable objects, marks them as “active,” and then clears unmarked objects.
- Incremental Marking: Splits the marking process into multiple steps, performed over several garbage collection cycles to reduce pause times.
- Concurrent Marking: Executes the marking process in parallel with the application, further reducing pause times.
- Generational Garbage Collection: Newly created objects are placed in the young generation, and if they survive for a period, they are moved to the old generation. The young generation is garbage collected more frequently, as most objects are short-lived.
Heap Memory Analysis
Node.js provides several tools to monitor and analyze heap memory usage, including --inspect, --inspect-brk, and the heapdump module.
// Manually generate a heap snapshot
const { heapdump } = require('heapdump');
heapdump.writeSnapshot('heapdump.hprof', (err, filename) => {
if (err) throw err;
console.log(`Heap dump written to ${filename}`);
});Non-Heap Memory Analysis
Monitoring non-heap memory is more complex, as it is not affected by garbage collection. The MemoryInfo interface in V8 can be used to retrieve non-heap memory usage.
const v8 = require('v8');
console.log(v8.getHeapStatistics());Memory Metrics
To view the memory usage of a process:
// Memory usage of the Node.js process
process.memoryUsage();
// System memory usage
os.totalmem(); // Total memory
os.freemem(); // Free memoryAnalyzing Memory Usage
const v8 = require('v8');
setInterval(() => {
const stats = v8.getHeapStatistics();
console.log(`Used heap size: ${stats.used_heap_size / 1024 / 1024} MB`);
}, 1000);Memory Leaks
Main Causes
- Cache: Unreleased memory in caches can lead to memory leaks as cache objects grow larger. Solutions include:
- Cache Restriction Policies: Use strategies like First-In-First-Out (FIFO) or Least Recently Used (LRU) to manage cache turnover.
- External Cache: Move caches to external storage to reduce the number of resident memory objects, improving garbage collection efficiency.
- Shared Cache: Allow processes to share caches.
- Explore Redis: Use Redis for efficient caching.
- Queue Consumption Lag: In task queues, if consumption is slower than production, memory objects accumulate, potentially causing leaks. Solutions include:
- Monitoring System: Set up alerts to notify relevant personnel when queues back up.
- Timeout Mechanism: Start a timer when tasks are added to the queue and respond with a timeout error if the task exceeds the time limit.
- Unreleased Scopes: Memory leaks caused by uncollected closures, global variables, or other unreleased scope variables.
Memory Leak Example
The heap stores reference types, such as strings and objects. In the following code, a Fruit object is stored in the heap.
// example.js
function Quantity(num) {
if (num) {
return new Array(num * 1024 * 1024);
}
return num;
}
function Fruit(name, quantity) {
this.name = name;
this.quantity = new Quantity(quantity);
}
let apple = new Fruit('apple');
print();
let banana = new Fruit('banana', 20);
print();When executed, the memory usage is as follows: the apple object uses only 4.21 MB of heapUsed, while banana creates a large array for its quantity property, causing heapUsed to spike to 164.24 MB.
$ node example.js
{"rss":"19.94 MB","heapTotal":"6.83 MB","heapUsed":"4.21 MB","external":"0.01 MB"}
{"rss":"180.04 MB","heapTotal":"166.84 MB","heapUsed":"164.24 MB","external":"0.01 MB"}Troubleshooting Methods
- node-heapdump: github.com/bnoordhuis/node-heapdump
- node-memwatch: github.com/lloyd/node-memwatch
Case Study: Memory Leak
Consider a simple HTTP server that creates a new timer for each request:
const http = require('http');
const server = http.createServer((req, res) => {
res.end('Hello, World!');
setInterval(() => {}, 1000); // Memory leak point
});
server.listen(3000);In this example, each request creates a new timer without a cleanup mechanism, leading to continuous memory growth.
Large Memory Applications
Node.js uses the Stream module to read and write applications with large memory requirements.
const fs = require('fs');
let reader = fs.createReadStream('in.txt');
let writer = fs.createWriteStream('out.txt');
reader.on('data', function (chunk) {
writer.write(chunk);
});
reader.on('end', function () {
writer.end();
});Cache Management
(Note: The original document does not provide specific content for this section. Based on context, this section would typically cover caching strategies to optimize memory usage, such as in-memory caching, external caching with tools like Redis, and cache eviction policies like LRU. Since no code or details are provided, this section is left as a placeholder for completeness.)
Scheduled Tasks
(Note: The original document does not provide specific content for this section. Based on context, this section would likely discuss implementing scheduled tasks in Node.js, such as using setInterval, setTimeout, or third-party libraries like node-cron for cron-like scheduling. Since no code or details are provided, this section is left as a placeholder for completeness.)



