Closed baryshev closed 12 years ago
I believe we're seeing the same error. Thanks @baryshev for your thorough testing and debugging!
I see no memory leaks with your example. You are however buffering up a lot of data, which explains the growing RSS.
I've said it before and I'll say it again: RSS is an extremely poor metric for determining memory leaks. malloc implementations are very reluctant to return memory to the system even under ideal circumstances (i.e. no heap fragmentation). Here is a gist that demonstrates that.
@bnoordhuis Do you know of any tool/technique to see what are these buffers that are being allocated and how we can hopefully reduce their amount?
@superfeedr You can use something node-inspector or node-heapdump to create and inspect heap snapshots.
Regarding the test case (which I'll post here for the sake of posterity):
var server = net.createServer(function (socket) {
socket.on('data', function() {
setTimeout(function() {
for (var i = 0; i < 100000; i++) {
var d = new Date();
socket.write(d.toString());
}
}, 10);
});
});
It writes data to the socket without checking the return value of write(). The core logic should be rewritten to something like this:
var i = 1e5;
function f() {
for (; i > 0; --i)
if (socket.write(d.toString()) === false) // the strict check is not optional
return socket.on('drain', f);
}
f();
@bnoordhuis But wait, I thought Buffers were outside of the heap? I understand RSS is not the right metric to check for leaks, but our heap just stays reasonnably small (at most 100MB), while RSS explodes (can go easily to 1GB). We want to know what's in there, because this growing RSS (whether it's a leak or not) causes trouble and forces the machine to start swapping.
But wait, I thought Buffers were outside of the heap?
Yes, but as of commit 6a128e0 (v0.8.12 and up) they're reported properly in heap snapshots.
Brilliant! Back to exploration. Thanks for the precious help. I expect though that they're not part of process.memoryUsage()'s heapTotal?
I expect though that they're not part of process.memoryUsage()'s heapTotal?
Indeed, but you can find out their total size with the statistics extension:
$ node --track_gc_object_stats -p 'Buffer(10*1024*1024); getV8Statistics()'
{ total_committed_bytes: 35635200,
new_space_live_bytes: 391880,
new_space_available_bytes: 656464,
new_space_commited_bytes: 1048576,
old_pointer_space_live_bytes: 524288,
old_pointer_space_available_bytes: 0,
old_pointer_space_commited_bytes: 524288,
old_data_space_live_bytes: 196608,
old_data_space_available_bytes: 0,
old_data_space_commited_bytes: 196608,
code_space_live_bytes: 1019904,
code_space_available_bytes: 0,
code_space_commited_bytes: 1019904,
cell_space_live_bytes: 98304,
cell_space_available_bytes: 0,
cell_space_commited_bytes: 98304,
lo_space_live_bytes: 0,
lo_space_available_bytes: 1498414848,
lo_space_commited_bytes: 0,
amount_of_external_allocated_memory: 10485816 } # <- this
@bnoordhuis how do i get access to that extension? I tried the command line above, and node tells me it doesn't recognize this flag --track_gc_object_stats. I tried this on 0.8.18 and 0.8.14. Thanks!
node --track_gc_object_stats -p -e 'Buffer(10_1024_1024); getV8Statistics();' Error: unrecognized flag --track_gc_object_stats Try --help for options
Buffer(10_1024_1024); getV8Statistics();
^
ReferenceError: getV8Statistics is not defined
at eval:1:23
at Object.
@spollack It's only available in the master branch, the V8 version in v0.8 is too old.
@bnoordhuis my rss is increasing, but amount_of_external_allocated_memory
stays low:
Before gc():
{"rss":265080832,"heapTotal":56172032,"heapUsed":8697768}
{
"total_committed_bytes": 57688064,
"new_space_live_bytes": 4027464,
"new_space_available_bytes": 12749592,
"new_space_commited_bytes": 33554432,
"old_pointer_space_live_bytes": 2159320,
"old_pointer_space_available_bytes": 12812072,
"old_pointer_space_commited_bytes": 14971392,
"old_data_space_live_bytes": 1095272,
"old_data_space_available_bytes": 1165208,
"old_data_space_commited_bytes": 2260480,
"code_space_live_bytes": 1219904,
"code_space_available_bytes": 1839808,
"code_space_commited_bytes": 3059712,
"cell_space_live_bytes": 31120,
"cell_space_available_bytes": 99952,
"cell_space_commited_bytes": 131072,
"lo_space_live_bytes": 0,
"lo_space_available_bytes": 1476361984,
"lo_space_commited_bytes": 0,
"amount_of_external_allocated_memory": 1081624
}
After gc():
{"rss":258056192,"heapTotal":49980416,"heapUsed":4513704}
{
"total_committed_bytes": 51396608,
"new_space_live_bytes": 2080,
"new_space_available_bytes": 16774976,
"new_space_commited_bytes": 33554432,
"old_pointer_space_live_bytes": 2127400,
"old_pointer_space_available_bytes": 6652376,
"old_pointer_space_commited_bytes": 8779776,
"old_data_space_live_bytes": 1802640,
"old_data_space_available_bytes": 457840,
"old_data_space_commited_bytes": 2260480,
"code_space_live_bytes": 1145440,
"code_space_available_bytes": 1914272,
"code_space_commited_bytes": 3059712,
"cell_space_live_bytes": 30304,
"cell_space_available_bytes": 100768,
"cell_space_commited_bytes": 131072,
"lo_space_live_bytes": 0,
"lo_space_available_bytes": 1482653440,
"lo_space_commited_bytes": 0,
"amount_of_external_allocated_memory": 1065128
}
heap dump file is around 250mb, but chrome says that it is only 5.1mb. What am I missing? My app processes around 20m simple requests per day and becomes less responsible (3ms on the first day -> up to 500ms on the third day). I don't use compiled modules, only redis and empty-gif.
node.js 0.10.10
@bobrik dead thread probably won't get you many responses. i'd say throw this on the mailing list. and some code is going to much more helpful.
@superfeedr Hi. It's pretty late, but were you able to figure out the reason? I'm facing this behavior in one of my apps as well:
I understand RSS is not the right metric to check for leaks, but our heap just stays reasonnably small (at most 100MB), while RSS explodes (can go easily to 1GB). We want to know what's in there, because this growing RSS (whether it's a leak or not) causes trouble and forces the machine to start swapping.
RSS memory doesn't release after doing some intensive tasks (highload).
My environment
How to reproduce leak
node server.js
.node client.js
.node server.js
rise up to 250-300Mb (or more).client.js
and wait some time to giveserver.js
time to complete all tasks.client.js
for a short time again, to get GC ofserver.js
work.Expected result
RSS memory will be released as well as a heap memory and will be comparable with initial values.
Actual result
Heap memory released successfully, but RSS memory not.
My results:
Before test:
After test:
Related discussions