I've noticed this a couple of times in a few of my scripts. Mainly scripts focusing around array iteration and manipulation.
I keep seeing massive memory leaks that eventually lead to the script running out of memory and dying. After inspection, it seems to be caused by a massive amount of TickObjects being created and not cleaned up.
A bit of reading pushed me to think that TickObject is an internal feature of node to manage asynchronous events. Is that what they're actually used for? Why would they spiral out of control? And how can it be prevented?
In case it helps, heres a dump (warning its around 312mb) https://www.dropbox.com/s/57t70t2igpo8kbi/heapdump-604700798.654094.heapsnapshot?dl=0 of an example where its spiralling out of control.
EDIT:
Managed to simplify the offending code. And strangely looks to be a combo of using process.stdout.write?
var a = Array(100)
.fill()
.map(_ => Math.round(Math.random()) ? true : false),
i = 0;
while (true) {
a.map(_ => !_);
process.stdout.write(`#${++i}\r`);
}
Run this and you'll quickly run out of memory. Is this behaviour to be expected? (I assume not) Or is it just weird behaviour with node?
Worked it out. The array was a red herring and in reality the actual problem was the process.stdout.write
On each write, an afterWrite clean up function is being queued up as a TickObject each time. As we never leave the Tick
/context we're in, this just amass till node explodes. Solution? Make any long/forever running code blocks asynchronous with ticks as well.
var a = Array(100)
.fill()
.map(_ => Math.round(Math.random()) ? true : false),
i = 0;
(function whileLoop () {
a.map(_ => !_);
process.stdout.write(`#${++i}\r`);
process.nextTick(whileLoop);
})();
Victory!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With