Memory leak when used array.push()

  • Version: v15.7.0
  • Platform: Microsoft Windows NT 10.0.19042.0 x64

What steps will reproduce the bug?

Launch the following script with node –expose-gc test.js

const array = [];

console.log(`${Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100} MB`);

for (let i = 0; i < 500; i++) {
    for (let j = 0; j < 50000; j++) {
        array.push('');
    }
}

console.log(`${Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100} MB`);

if (global.gc) {
    global.gc();
}

const map = new Map();

console.log(`${Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100} MB`);

for (let i = 0; i < 500; i++) {
    for (let j = 0; j < 50000; j++) {
        map.set(i, j);
    }
}

console.log(`${Math.round((process.memoryUsage().heapUsed / 1024 / 1024) * 100) / 100} MB`);

How often does it reproduce? Is there a required condition?

All the time

What is the expected behavior?

The heap not to be 767.58 MB

What do you see instead?

2.91 MB
767.58 MB
2.56 MB
2.88 MB

2 thoughts on “Memory leak when used array.push()

  1. It looks like V8 can reclaim all of the memory, so I don’t think it’s a leak. I think the memory spike you’re seeing is the memory used by V8 to store the array, as well as garbage generated by calling push() so many times.

  2. That is, this script:

    console.log('Node.js', process.version)
    console.log(`${(process.memoryUsage().heapUsed / 2**20).toFixed(2)} MiB`);
    const tick = () => {
      console.time()
      const array = [];
      for (let i = 0; i < 500; i++) {
          const r = []
          for (let j = 0; j < 50000; j++) r.push('')
          array.concat(r);
      }
      console.timeEnd()
      console.log(`${(process.memoryUsage().heapUsed / 2**20).toFixed(2)} MiB`);
      setTimeout(tick, 100)
    }
    tick()

    Is ~2 times slower on Node.js 15.x than on Node.js 10.x on my machine. Something changed between 11.x and 12.0.0.