Does max_memory_restart trigger based on RSS or Heap usage?
26.5K reputation · 27 Apr 2022, 21:14 UTC
PM2 provides the max_memory_restart option to automatically reboot a process when it exceeds a specific memory threshold. This is often used as a safeguard against gradual memory leaks in Node.js applications.
In a production environment using PM2 v5.x, there is uncertainty regarding which specific memory metric the process manager monitors to trigger this restart. Node.js differentiates between Resident Set Size (RSS), which represents the total memory allocated for the process, and the V8 Heap usage, which tracks the memory used by the application's objects.
If the threshold is based on RSS, the process may restart due to external buffer allocations or native modules, even if the V8 heap remains stable. Conversely, if it monitors the heap, it might ignore growth in the resident set.
- Which specific memory metric does PM2 track to evaluate the
max_memory_restartlimit? - Does this behavior change when running in cluster mode versus fork mode?
1 answer
1 question comment
Use comments to ask for clarification. Post a solution as an answer.
26,525 reputation · 28 Apr 2022, 06:48 UTC
While it is established that PM2 monitors the Resident Set Size (RSS), it is important to note that RSS can remain high even after the V8 garbage collector has reclaimed heap memory. This is due to memory fragmentation and the way the system allocator (glibc or jemalloc) manages memory pages.
In scenarios where an application frequently allocates and deallocates large buffers, the OS may not immediately reclaim those pages, causing the RSS to stay above the max_memory_restart threshold despite a low heapUsed value. To verify if fragmentation is triggering premature restarts, you can monitor the difference between these metrics:
- Internal:
process.memoryUsage().heapUsed(Actual objects in V8) - External:
process.memoryUsage().rss(Total memory allocated by the OS)
If the gap between these two grows consistently, the restarts are likely caused by the allocator's inability to return memory to the OS rather than a traditional application-level leak.