1

I have a NodeJS server running on a small VM with 256MB of RAM and I notice the memory usage keeps growing as the server receives new requests. I read that an issue on small environments is that Node doesn't know about the memory constraints and therefore doesn't try to garbage collect until much later (so for instance, maybe it would only want to start garbage collecting once it reaches 512MB of used RAM), is it really the case?

I also tried using various flags such as --max-old-space-size but didn't see much change so I'm not sure if I have an actual memory leak or if Node just doesn't GC as soon as possible?

Pop Flamingo
  • 3,023
  • 2
  • 26
  • 64
  • Try adding more space to the APP and GC is invoked by JVM as soon as HEAP started to become full in order to free the memory for subsequent requests or operations. – Apoorva Chikara Jul 17 '22 at 04:44
  • It GCs when it's idle for a bit of time or when it is an emergency and running low on memory. Process memory usage does not allow you to see garbage collection because memory that has been GCed may not be returned to the OS, but may remain in the heap as a free block and available for future allocation within that heap. To track an actual leak, you have to first know that you don't have any internal memory structures that are growing. Then, you have see the actual internal heap statistics continually rising over a long period of time and never stabilizing. – jfriend00 Jul 17 '22 at 05:36
  • It is normal for memory usage to rise for awhile until a working set is in place and then stop climbing after that. Of course, if you have any internal data structures that continually grow, that would consume more memory over time without really being a leak, but rather just an accumulation of more and more data in memory. – jfriend00 Jul 17 '22 at 05:37

1 Answers1

3

This might not be a complete answer, but it's coming from experience and might provide some pointers. Memory leak in NodeJS is one of the most challenging bugs that most developers could ever face.

But before we talk about memory leak, to answer your question - unless you explicitly configure --max-old-space-size, there are default memory limits that would take over. Since certain phases of Garbage collection in node are expensive (and sometimes blocking) steps, depending upon how much memory is available to it, it would delay (e.g. mark-sweep collection) some of the expensive GC cycles. I have seen that in a Machine with 16 GB of memory it would easily let the memory go as high as 800 MB before significant Garbage Collections would happen. But I am sure that doesn't make ~800 MB any special limit. It would really depend on how much available memory it has and what kind of application are you running. E.g. it is totally possible that if you have some complex computations, caches (e.g. big DB Connection Pools) or buggy logging libraries - they would themselves always take high memory.

If you are monitoring your NodeJs's memory footprint - sometime after the the server starts-up, everything starts to warm up (express loads all the modules and create some startup objects, caches warm up and all of your high memory consuming modules became active), it might appear as if there is a memory leak because the memory would keep climbing, sometimes as high as ~1 gb. Then you would see that it stabilizes (this limit used to be lesser in <v8 versions).

But sometimes there are actual memory leaks (which might be hard to spot if there is no specific pattern to it).

In your case, 256 MB seems to be meeting just the minimum RAM requirements for nodejs and might not really be enough. Before you start getting anxious of memory leak, you might want to pump it up to 1.5 GB and then monitor everything.

Some good resources on NodeJS's memory model and memory leak.

Some debugging tools to help spot the memory leaks

Tintin
  • 2,853
  • 6
  • 42
  • 74
  • Thank you for the detailed answer! I would say my app isn't very complicated, it is a Discord bot using discord.js, axios for API calls, and a few other utility libs, however its perfectly possible one of them might have a memory leak indeed. I think I will try to experiment with different RAM configs and use `--max-old-space-size` again to see what happens over a longer period of time. I did try to use the Chrome devtools memory inspector but I had a hard tile finding anything clearly wrong especially since the part that grow the most (I think it was "compiled") was pretty cryptic to me. – Pop Flamingo Jul 17 '22 at 23:52
  • 1
    Thanks to one of your links I discovered `--trace_gc ` and if I understand it correctly maybe there is no leak after all: at program start there was a few mark and sweeps, but then I only see scavenges so I suppose the mark and sweep isn't triggered really easily and therefore the memory keeps growing. – Pop Flamingo Jul 18 '22 at 00:35