Search code examples
node.jsdockerubuntumemory-managementv8

Resident memory greater than --max-old-space-size threshold?


I'm running a dockerised node.js application on my server, using the --max-old-space-size option to limit the applications heap size. The following output is given by htop:

  PID USER      PRI  NI  VIRT   RES   SHR S CPU% MEM%   TIME+  Command
10158 root       20   0  4284   720   644 S  0.0  0.0  0:00.00 sh -c node --max-old-space-size=512 ./dist/www.js
10159 root       20   0 1841M  929M 29592 S  0.0  3.0  1h31:16 node --max-old-space-size=512 ./dist/www.js
10160 root       20   0 1841M  929M 29592 S  0.0  3.0  0:00.00 node --max-old-space-size=512 ./dist/www.js
10161 root       20   0 1841M  929M 29592 S  0.0  3.0  7:27.13 node --max-old-space-size=512 ./dist/www.js
10162 root       20   0 1841M  929M 29592 S  0.0  3.0  7:26.96 node --max-old-space-size=512 ./dist/www.js
10163 root       20   0 1841M  929M 29592 S  0.0  3.0  7:26.99 node --max-old-space-size=512 ./dist/www.js
10164 root       20   0 1841M  929M 29592 S  0.0  3.0  7:26.64 node --max-old-space-size=512 ./dist/www.js

You can see my applications resident memory (929M) is way above my max-old-space-size value (512MB) so why is this being seen? Shouldn't the application have aborted by this point?

System Info

Docker version: 19.03.5
node image version: 11.13.0

uname -v
#31~18.04.1-Ubuntu SMP Tue Nov 17 10:48:34 UTC 2020

Solution

  • V8 developer here. The --max-old-space-size flag does not directly control the overall process' memory consumption; it puts a limit on one part (the biggest part) of V8's managed (i.e. garbage-collected) heap, which is the chunk of memory where all the JavaScript objects are put. Aside from this "old space", V8 also has a (much smaller) "new space"; and besides V8's managed heap, there are a bunch of other consumers of memory in the process: for example, within V8, parser and compiler use memory outside the managed heap; and then aside from V8, Node puts a bunch of things in memory too. Depending on what exactly the embedder (i.e. Node) and the executing code do, large strings and ArrayBuffers can also live outside of the managed heap.

    In short, --max-old-space-size gives you one knob to affect how much memory will be used, but the limit you set there is not a limit for the process' overall memory consumption. (For comparison, in Chrome, typically about a third of a renderer process' memory is V8's managed heap, though depending on what websites do there are significant outliers in both directions. I don't know typical numbers for Node.)