Home > Blockchain >  Mongo call leading to node js memory leak
Mongo call leading to node js memory leak

Time:09-08

When I run await Order.find({}), which returns 22k documents, the used_heap_size goes up to around 430mb from around 50mb.

It never seems to go back down.

Shouldn't the used_heap_size go back down pretty soon? I'm not sure if this is defined as a memory leak, but it seems like it. What causes this? Is this normal?

  app.get('/orders', async (req, res, next) => {
    v8Print('before find orders');
    const j = await Order.find({});
    v8Print('afters find orders');
    res.sendStatus(200);
  });
  app.get('/logMem', async (req, res, next) => {
    v8Print('memory info');

    res.sendStatus(200);
  });

Log function

const v8 = require('v8');

// for memory allocation heap debugging
module.exports.v8Print = (message) => {
  const heapStats = v8.getHeapStatistics();
  const heapStatsMB = heapStats;
  for (const key in heapStatsMB) {
    heapStatsMB[key] = `${(((heapStatsMB[key] / 1024 / 1024) * 100) / 100).toFixed(2)} MB`;
  }
  console.log('');
  console.log(message);
  console.table(heapStatsMB);
  console.log('');
};

before find orders
┌─────────────────────────────┬──────────────┐
│           (index)           │    Values    │
├─────────────────────────────┼──────────────┤
│       total_heap_size       │  '54.05 MB'  │
│ total_heap_size_executable  │  '0.80 MB'   │
│     total_physical_size     │  '53.71 MB'  │
│    total_available_size     │ '1999.10 MB' │
│       used_heap_size        │  '49.56 MB'  │
│       heap_size_limit       │ '2048.00 MB' │
│       malloced_memory       │  '0.01 MB'   │
│    peak_malloced_memory     │  '2.48 MB'   │
│      does_zap_garbage       │  '0.00 MB'   │
│  number_of_native_contexts  │  '0.00 MB'   │
│ number_of_detached_contexts │  '0.00 MB'   │
└─────────────────────────────┴──────────────┘

afters find orders
┌─────────────────────────────┬──────────────┐
│           (index)           │    Values    │
├─────────────────────────────┼──────────────┤
│       total_heap_size       │ '521.66 MB'  │
│ total_heap_size_executable  │  '1.05 MB'   │
│     total_physical_size     │ '520.90 MB'  │
│    total_available_size     │ '1611.12 MB' │
│       used_heap_size        │ '435.79 MB'  │ // <---435 after Orders.find
│       heap_size_limit       │ '2048.00 MB' │
│       malloced_memory       │  '0.01 MB'   │
│    peak_malloced_memory     │  '2.93 MB'   │
│      does_zap_garbage       │  '0.00 MB'   │
│  number_of_native_contexts  │  '0.00 MB'   │
│ number_of_detached_contexts │  '0.00 MB'   │
└─────────────────────────────┴──────────────┘
memory info
┌─────────────────────────────┬──────────────┐
│           (index)           │    Values    │
├─────────────────────────────┼──────────────┤
│       total_heap_size       │ '521.66 MB'  │
│ total_heap_size_executable  │  '1.05 MB'   │
│     total_physical_size     │ '520.90 MB'  │
│    total_available_size     │ '1610.56 MB' │
│       used_heap_size        │ '436.35 MB'  │ // <--- stays around 435
│       heap_size_limit       │ '2048.00 MB' │
│       malloced_memory       │  '0.01 MB'   │
│    peak_malloced_memory     │  '2.93 MB'   │
│      does_zap_garbage       │  '0.00 MB'   │
│  number_of_native_contexts  │  '0.00 MB'   │
│ number_of_detached_contexts │  '0.00 MB'   │
└─────────────────────────────┴──────────────┘

CodePudding user response:

V8 will only GC if it needs to free up space. By default Node is given ~2GB of memory so it's not under much pressure from your 435mb of objects.

You can force a GC by running your server as node --expose-gc server.js which exposes a gc function on the global.

const v8 = require('v8');

// for memory allocation heap debugging
module.exports.v8Print = (message) => {
  global.gc(); // <-- Call this before reading heap info
  const heapStats = v8.getHeapStatistics();
  const heapStatsMB = heapStats;
  for (const key in heapStatsMB) {
    heapStatsMB[key] = `${(((heapStatsMB[key] / 1024 / 1024) * 100) / 100).toFixed(2)} MB`;
  }
  console.log('');
  console.log(message);
  console.table(heapStatsMB);
  console.log('');
};

// ...

app.get('/orders', async (req, res, next) => {
  v8Print('before find orders'); // ~50MB
  let j = await Order.find({}); // Use `let` merely so we can set it to `undefined` later
  v8Print('afters find orders'); // ~435MB
  j = undefined; // Remove reference so it can be GC'd
  v8Print('afters clean up'); // ~50MB
  res.sendStatus(200);
});
app.get('/logMem', async (req, res, next) => {
  v8Print('memory info'); // ~50MB
  res.sendStatus(200);
});
  • Related