Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Node.JS memory leak with PM2

I was running my server with pm2 start ... and pm2 monit was showing me 3GB memory after 2 hours. So I attached memwatch, now I waited for another 2 hours and again the memory shown by pm2 monit reached 3GB.

So, I checked the logs memwatch generated. Showed me:

{ before: { nodes: 75659, size_bytes: 11141702, size: '10.63 mb' },
  after: { nodes: 73226, size_bytes: 10840598, size: '10.34 mb' },
  change:
   { size_bytes: -301104,
     size: '-294.05 kb',
     freed_nodes: 5141,
     allocated_nodes: 2708,

And another:

{ before: { nodes: 72591, size_bytes: 10728318, size: '10.23 mb' },
  after: { nodes: 73284, size_bytes: 10798062, size: '10.3 mb' },
  change:
   { size_bytes: 69744,
     size: '68.11 kb',
     freed_nodes: 5931,
     allocated_nodes: 6620,

Now I am really confused, those are the last logs so I'm pretty sure those are the logs generated when pm2 monit showed the huge memory leak.

So, why is memwatch showing me 10MB+ memory and pm2 monit showing 3GB+?


Now switching to something like forever or monit to see if the leak still exists.


A bit more background

  • I have been trying to profile and find the leak and there isn't just any leak showing on the profiles.
  • The memwatch diff is started when a client connects and the difference is taken when the client disconnects.
like image 454
majidarif Avatar asked Feb 15 '15 01:02

majidarif


People also ask

Why we use PM2 in node JS?

PM2 is a Node. js process manager that comes with a built-in load balancer. It helps facilitate production deployments and enables you to keep running applications alive indefinitely (even when accidents occur).

What causes memory leaks JS?

Circular references are a common cause of memory leaks. Internet Explorer 6 and 7 are known to have reference-counting garbage collectors, which have caused memory leaks with circular references. No modern engine uses reference-counting for garbage collection anymore.

What is PM2 in node JS?

PM2 is a production process manager for Node. js applications with a built-in load balancer. It allows you to keep applications alive forever, to reload them without downtime and to facilitate common system admin tasks.


2 Answers

  • I was also facing the same issue, but after little research i found that nodejs is not calling the garbage collector when using pm2.
  • So, until PM2 fixes that issue temporary work around is force call garbage collector, using following

pm2 start app.js --node-args='--expose-gc'

Above argument --expose-gc will allow us to force call garbage collector from node js, now use following code for force garage collection.

if (global.gc) {
   global.gc();
} else {
   console.log('Garbage collection unavailable.  use --expose-gc '
   + 'when launching node to enable forced garbage collection.');
}  

This will solve PM2 meomry leak problem.

like image 80
Vinay Kharecha Avatar answered Sep 21 '22 09:09

Vinay Kharecha


There are a lot of really bad answers on this thread. Really, really bad.

The answer is simple: your code has a memory leak that you need to find and remove, and it's VERY UNLIKELY that the GC is wrong, it's far more likely your code is the culprit.

So first off:

  1. "I found that with PM2 the garbage collector doesn't work" - this is patently nonsensical, PM2 runs node, which uses V8, which has its own garbage collector built-in. This isn't disabled just because you run PM2.
  2. "So until that is fixed call the GC" - No! Calling the GC manually is lazy if your code has leaks, you should fix them.
  3. "After removing pm2 there is no more memory leak for now." - No, you're simply not monitoring it in PM2; the leak will still be there, you just don't see the error because you're running it using node and not looking at the results.

Secondly, the actual solution should be:

Profile your code's memory and CPU usage using the tool of your choice. For most people, that is going to be Chrome's debugging tools connected to the running node instance, and look at which functions are causing memory usage to spike. Simply calling the GC manually is lazy because your code still has a leak but you're just telling V8 to constantly hoover up memory after your app leaks it, which is very lazy practice.

like image 38
user-12410035 Avatar answered Sep 17 '22 09:09

user-12410035