When my node js server is running via pm2, it has a higher memory usage reading than the actual memory heap in the application when inspected in DevTools. More so, the value under memory
in pm2 slowly increases over time, possibly indicating some kind of memory leak. This slow increase in memory usage also cannot be observed in DevTools.
Any explanation and/or solutions to these two (seemingly) strange occurrences?
This is my DevTools
This is pm2 list
here is my javascript
code
var SSE = require('sse');
var https = require('https');
var fs = require('fs');
var url = require('url');
var mysql = require('mysql');
var schedule = require('node-schedule');
var options = {
key: fs.readFileSync('pathto/ssl.key'),
cert: fs.readFileSync('pathto/ssl.crt'),
ca: fs.readFileSync('pathto/ssl.ca-bundle')
};
var pool = mysql.createPool({
connectionLimit: 100,
host: "host",
user: "user",
password: "pass",
database: "db"
});
async function connectandrun() {
try {
var server = https.createServer(options, function(req, res) {
var queryData = url.parse(req.url, true).query;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,OPTIONS',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
});
if (queryData.connectionid) {
var connecitonid = queryData.connectionid;
} else {
var connecitonid = "";
}
var myconection = "myconnecction" + connecitonid;
var uuserjson = {};
uuserjson[myconection] = {
Data: {
Element: null
}
};
schedule.scheduleJob('*/3 * * * * *', function() {
var runninginstance = main(uuserjson, queryData, myconection, res).catch(console.error);
runninginstance = null;
});
res.on("close", function() {
res.end();
uuserjson[myconection] = null;
myconection = null;
connecitonid = null;
});
});
server.listen(3000, '0.0.0.0', function() {
var sse = new SSE(server);
sse.on('connection', function(client) {
client.send('hi there!');
});
});
} finally {}
}
connectandrun().catch(console.error);
async function main(uuserjson, queryData, myconection, res) {
pool.getConnection(function(err, con) {
if (err) {
console.log(err);
} else {
con.query("MYSQL QUERY",
function(err, result, fields) {
if (err) throw err;
if (result.length != 0) {
uuserjson[myconection] = {
Data: {
Element: result[0]
}
};
if (result[0]) {
res.write("retry: 30000\n\n" + "event: blanks\ndata: " + result[0] + "\n\n");
}
}
con.release();
});
}
});
}
When my node js server is running via pm2, it has a higher memory usage reading than the actual memory heap in the application when inspected in DevTools. More so, the value under memory
in pm2 slowly increases over time, possibly indicating some kind of memory leak. This slow increase in memory usage also cannot be observed in DevTools.
Any explanation and/or solutions to these two (seemingly) strange occurrences?
This is my DevTools
This is pm2 list
here is my javascript
code
var SSE = require('sse');
var https = require('https');
var fs = require('fs');
var url = require('url');
var mysql = require('mysql');
var schedule = require('node-schedule');
var options = {
key: fs.readFileSync('pathto/ssl.key'),
cert: fs.readFileSync('pathto/ssl.crt'),
ca: fs.readFileSync('pathto/ssl.ca-bundle')
};
var pool = mysql.createPool({
connectionLimit: 100,
host: "host",
user: "user",
password: "pass",
database: "db"
});
async function connectandrun() {
try {
var server = https.createServer(options, function(req, res) {
var queryData = url.parse(req.url, true).query;
res.writeHead(200, {
'Content-Type': 'text/event-stream',
'Access-Control-Allow-Origin': '*',
'Cache-Control': 'no-cache',
'Connection': 'keep-alive',
'Access-Control-Allow-Methods': 'GET,PUT,POST,DELETE,OPTIONS',
'Access-Control-Allow-Headers': 'Origin, X-Requested-With, Content-Type, Accept'
});
if (queryData.connectionid) {
var connecitonid = queryData.connectionid;
} else {
var connecitonid = "";
}
var myconection = "myconnecction" + connecitonid;
var uuserjson = {};
uuserjson[myconection] = {
Data: {
Element: null
}
};
schedule.scheduleJob('*/3 * * * * *', function() {
var runninginstance = main(uuserjson, queryData, myconection, res).catch(console.error);
runninginstance = null;
});
res.on("close", function() {
res.end();
uuserjson[myconection] = null;
myconection = null;
connecitonid = null;
});
});
server.listen(3000, '0.0.0.0', function() {
var sse = new SSE(server);
sse.on('connection', function(client) {
client.send('hi there!');
});
});
} finally {}
}
connectandrun().catch(console.error);
async function main(uuserjson, queryData, myconection, res) {
pool.getConnection(function(err, con) {
if (err) {
console.log(err);
} else {
con.query("MYSQL QUERY",
function(err, result, fields) {
if (err) throw err;
if (result.length != 0) {
uuserjson[myconection] = {
Data: {
Element: result[0]
}
};
if (result[0]) {
res.write("retry: 30000\n\n" + "event: blanks\ndata: " + result[0] + "\n\n");
}
}
con.release();
});
}
});
}
Share
Improve this question
edited Dec 25, 2019 at 2:29
user2993497
asked Dec 25, 2019 at 1:38
user2993497user2993497
5851 gold badge7 silver badges22 bronze badges
15
- and what about the memory leak? my application is always around 9-11MB. But pm2's memory seems to be increasing with time? – user2993497 Commented Dec 25, 2019 at 1:51
- That I'm unsure of. It's hard to diagnose a memory leak without any code... It could be some pm2 overhead? – Matt Oestreich Commented Dec 25, 2019 at 2:02
- 1 Sounds good - I need to do some research as well since I have been using pm2 (but have memory limits set so if RAM researches a certain threshold I auto restart pm2).. so something like this would have been hard for me to catch. Nice find!! – Matt Oestreich Commented Dec 25, 2019 at 2:46
- 1 Okay, I can confirm there seemed to be some kind of leak on pm2. I tried it on Passenger and the memory stayed stagnant. In your answer, can you talk a little about the discussions and rumours out there about pm2 leaking? and provide the solutions / alternatives you found. Thanks for pointing that out – user2993497 Commented Dec 25, 2019 at 17:14
- 1 Nice work - I have just finished my write-up on this. Glad we (mostly you) were able to figure this out. Hi-Five for teamwork! lol – Matt Oestreich Commented Dec 25, 2019 at 18:32
2 Answers
Reset to default 19After teaming up with OP on this, it has been confirmed there is some sort of memory leak in PM2
.
Please see the below 'write-up' on our findings:
The Issue:
- Slowly over time
PM2
uses more and more RAM- This points to some sort of memory leak
Evidence & Rumors:
- When running the application without
PM2
, just usingnode myserver.js
, there is no evidence of RAM slowly increasing over time- RAM remains flat
- The application that was used to test this theory is a small web app, in order to minimize the chance that the code contains a memory leak, and that the leak is in fact coming from
PM2
- There have been 'rumors' and evidence of memory leaks in
PM2
for quite some time now - going back as far as 4 years (this answer was written in December 2019) - Someone describing why they stopped using
PM2
- See last comment
- Thread where others are describing similar issues
- That do not occur when
PM2
is NOT used
- That do not occur when
- Bug filed on
PM2
GitHub with a confirmed memory leak- This bug was filed this year [2019] and at the time of this writing has comments as recent as October, where someone describes how this is still an issue
PM2 Alternatives You Should Consider:
Phusion Passenger
seems like a strong candidate for replacingPM2
- `Quick-start guide can be found here
- Phusion Passenger looks like the closest comparison to
PM2
and is where I would start - No, I do not have any affiliation with Phusion Passenger...
Forever
- Does not seem like it is actively being maintained (in some of the issues filed on their GitHub people recommend using other apps)
Nodemon
- Not really 'apples to apples' with
PM2
, but hey, variety is the spice of life
- Not really 'apples to apples' with
Naught
- Does not appear to be actively maintained and is kind of 'small' in terms of stars
- Native
Node.js
cluster
PM2
Workarounds/Band-Aids: (!not recommended to rely on these in Production!)
- Set a Memory Threshold to auto-reload
PM2
once X amount of RAM has been consumed- This 'feature' is native within
PM2
- This 'feature' is native within
- Use a Cron Job to restart
PM2
every X hours- Another example of a Cron Job
I had the same error. The problem was that the NextJS
build was not completed successfully. I did not notice this and tried to run pm2
. Use command:
npm run build
And make sure the build completes successfully.