Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Are there memory leaks with javascript call a function in a callback recursively?

Let's say, for example, you are writing a program that waits for a message on a queue, handles it, and then waits for the next message, and this goes on forever. In a language like C or Java it would look something like this:

void processMessage() {
    while (true) {
        // waitForMessage blocks until the next message is received
       msg = waitForMessage(); 
      // handle msg here
    }
}

In Javascript (I'm using node.js, btw), because callbacks are used, it normally looks like this:

function processMessage() {
    waitForMessage(function(msg) {
        // handle msg or error here
        processMessage();
    }); 
}

My worry is that you basically have a chain of callbacks that recursively call the original function and the overhead of doing so might slowly eat up memory. I'm guessing this isn't actually a problem since maybe javascript callbacks exist on their own stack independently and are not pushed on to the stack of the original functions? Someone explain javascript callbacks and scoping to me and assure me that the javascript code will not run out of memory when run for an arbitrarily long amount of time while receiving an arbitrarily large number of messages

like image 703
Mike Avatar asked May 15 '15 15:05

Mike


People also ask

Can recursion cause memory leak?

From the previous example, we can see that recursive calls in co or async functions may delay the memory deallocation. This delay leads to memory pileups and memory pressure.

Are memory leaks possible in JavaScript?

If your JavaScript application is experiencing frequent crashes, high latency, and poor performance, one potential cause could be memory leaks.

What happens to the memory during recursion?

Memory Allocation of Recursive Functions. A recursive function calls itself, so the memory for a called function is allocated on top of the memory allocated for calling the function. Remember, a different copy of local variables is created for each function call.

Does recursive use more memory?

Recursion is usually slower than iteration due to the overhead of maintaining the stack. Recursion uses more memory than iteration.


2 Answers

No, recursive function calls do not cause memory leaks in Javascript.

The only memory used by a function call is a bit of stack space (so the interpreter knows where to go when the function returns) and whatever memory is used by the scope object of the function (e.g. the local variables). That stack memory is completed returned to the system when the function call returns. It does not leak.

In JavaScript, with asynchronous callbacks, the initiating function has already returned and thus the stack has been cleared long before the asynchronous callback has been called so there is no build up of the stack.

There will be a function scope object in memory until the callback is done and that is important and is required to allow the inline callback to have access to the variables declared in its parent scope. As soon as the callback is done (not reachable any more), that scope object will be garbage collected. Unless you are doing something unusual such as allocated giant strings or buffers in that temporary scope, the memory usage of that scope should not be an issue.

As for retrieving many messages from one initial function call and then repeated calls of the same callback, keep in mind that the parent function is just executed once and just one scope object is allocated no matter how many times the callback is called so there is no build up of memory for each time the callback is called. The callback itself will get a new function scope each time it is called, but since the callback itself doesn't trigger any asynchronous calls, that scope object will be temporary and will be eligible for garbage collection as soon as the callback is done with its work and returns.

If you chain/embed asynchronous operations inside each other, then additional scope objects will be retained for the duration of the asynchronous operation, but this is how Javascript works and is what offers the features of having access to your parent scope. In practice, it has not generally proven to be a memory issue. Scope objects by themselves are relatively compact objects (one is created for nearly every function call) so as I said above as long as you don't put giant buffers or giant strings/arrays into a persisting scope, the memory usage is usually not relevant.


Also keep in mind that when you call processMessage() again from within the asynchronous callback that isn't the kind of recursion that you might generally think of because the previous function call to processMessage() has already returned and the stack has completely unwound before the asynchronous event triggered the callback. So, there is no stack build-up in this case. This is because asynchronous operations in Javascript all run through an event queue. When an asynchronous operation is ready to trigger an action, it puts an event in the Javascript event queue. That event is only processed when the current thread of JS operation has finished and completely unwound. Only then does the JS interpeter look in the event queue to see if there is something else to do. As such, the stack is always completely unwound before the next asynchronous operation is triggered.

For more info on how this works and a number of reference articles on the JS event queue (which works the same in node.js that it does in the browser), see this article:

How does JavaScript handle AJAX responses in the background?

This is one of the reasons that Joyent calls node.js an "an event-driven, non-blocking I/O model" right on the node.js home page.

like image 60
jfriend00 Avatar answered Oct 27 '22 22:10

jfriend00


Functions aren't allocated on the stack. The callback function will be garbage collected after it's been used unless a reference is kept for some reason. Your code should be just fine!

like image 44
ReyCharles Avatar answered Oct 27 '22 21:10

ReyCharles