process.memoryUsage()

Reports the memory the Node.js process is using, in bytes, broken down by heap, RSS and external allocations.

Signature
process.memoryUsage()
  • Added in Node.js v0.1.16

Return value

ObjectAn object with the integer byte counts rss, heapTotal, heapUsed, external and arrayBuffers.

Changelog

  • PHP v13.9.0Added arrayBuffers to the returned object (also in v12.17.0).
  • PHP v7.2.0Added external to the returned object.

process.memoryUsage() returns a snapshot of memory use in bytes. Reading the fields correctly is most of the value:

  • rss — Resident Set Size, everything the process occupies in physical memory: JS heap, C++ objects, code, stacks. This is the number a container's memory limit kills you on.
  • heapTotal — how much V8 has reserved for the JS heap.
  • heapUsed — how much of that is live. The one to trend when hunting a leak.
  • external — memory of C++ objects bound to JS objects.
  • arrayBuffers — memory behind ArrayBuffers and Buffers; already counted inside external, so do not add them together.

What trips people up

A single reading means almost nothing — GC timing makes consecutive calls jump around. Sample over time and look at the trend of heapUsed after collections instead. Growing rss with flat heapTotal is often glibc malloc fragmentation on Linux, not a JS leak.

The call is not free: it walks each memory page, so it can be slow in a large process. Do not put it in a hot path; sample on an interval. If you only need RSS, process.memoryUsage.rss() (v15.6.0) is faster.

Under Worker threads, rss covers the entire process while the other fields describe the calling thread.

Example

Try it yourself
Loading editor…
Press Run to execute the code.

When to use it

  • Sample heapUsed on an interval to see whether a long-running service is leaking.
  • Log RSS next to a container's memory limit to explain an OOM kill.
  • Compare memory before and after a change to a batch import.
  • Expose a /metrics endpoint that reports heap and RSS to a monitoring system.

Frequently asked questions

What is the difference between rss and heapUsed?

rss is the total physical memory the whole process occupies, including V8's heap, C++ objects, Buffers and code, while heapUsed counts only live JavaScript objects inside V8's heap. A container OOM kill is triggered by rss, so watch that against your memory limit and use heapUsed to find JavaScript-level leaks.

Are process.memoryUsage() values in bytes or megabytes?

Bytes. Divide by 1024 twice for megabytes, as in `(usage.heapUsed / 1024 / 1024).toFixed(1)`.

Why does memory keep growing even though my code has no leak?

On Linux with glibc, sustained rss growth alongside a stable heapTotal is usually allocator fragmentation rather than a JavaScript leak, and Node documents switching to an alternative malloc such as jemalloc as the fix. V8 also grows the heap opportunistically and returns it lazily, so a rise that plateaus is normal.

More examples

A readable memory report

The output shows why heapUsed alone is a misleading leak metric: allocating 100 MB of Buffers barely moves heapUsed, because Buffer storage lives outside the V8 heap and appears in arrayBuffers (and inside external) while showing up in rss. A service that leaks Buffers therefore gets OOM-killed with a heap graph that looks perfectly flat.

Example · javascript
const mb = (bytes) => `${(bytes / 1024 / 1024).toFixed(1)} MB`;

function report(label) {
  const m = process.memoryUsage();
  console.log(
    `${label.padEnd(12)} rss=${mb(m.rss).padStart(9)}  ` +
    `heapUsed=${mb(m.heapUsed).padStart(9)}  ` +
    `heapTotal=${mb(m.heapTotal).padStart(9)}  ` +
    `arrayBuffers=${mb(m.arrayBuffers)}`
  );
}

report('startup');

const buffers = Array.from({ length: 20 }, () => Buffer.alloc(5 * 1024 * 1024));
report('allocated');

buffers.length = 0;
global.gc?.(); // run with --expose-gc to force a collection
report('released');
// startup      rss=  42.1 MB  heapUsed=   4.3 MB  heapTotal=   6.1 MB  arrayBuffers=0.0 MB
// allocated    rss= 146.8 MB  heapUsed=   4.6 MB  heapTotal=   6.4 MB  arrayBuffers=100.0 MB
// released     rss=  47.2 MB  heapUsed=   4.4 MB  heapTotal=   6.4 MB  arrayBuffers=0.0 MB

Trending heapUsed to spot a leak

The output shows the signature of a real leak: heapUsed climbing monotonically across samples that each follow a garbage collection opportunity, rather than sawtoothing back down. A single reading could not show this. In production the same pattern is what you graph — sample every 30 seconds and alert on a rising floor, not on any individual peak.

Example · javascript
const leaked = [];
let sample = 0;

const timer = setInterval(() => {
  // Simulated leak: every tick retains more data.
  for (let i = 0; i < 20000; i++) leaked.push({ id: i, at: sample });

  const { heapUsed } = process.memoryUsage();
  console.log(`sample ${++sample}: heapUsed ${(heapUsed / 1024 / 1024).toFixed(1)} MB, retained ${leaked.length}`);

  if (sample === 5) clearInterval(timer);
}, 500).unref();
// sample 1: heapUsed 7.9 MB, retained 20000
// sample 2: heapUsed 11.2 MB, retained 40000
// sample 3: heapUsed 14.6 MB, retained 60000
// sample 4: heapUsed 18.0 MB, retained 80000
// sample 5: heapUsed 21.3 MB, retained 100000

Discussion

  • Be the first to comment on this lesson.