17

I've done some tests with my node.js application looking for memory leak that my code supposed to do. I run script that in my opinion should leak memory, but I am surprised by the result.

redisClient.on('message', initRequest);

function onSuccess(self, json){
    console.dir(json);
}

function initRequest(channel, message){

  var request = new RequestObject({
      redisMessage: message
  });
  
  request.on('success', onSuccess);

}

redisClient emits a couple of 'message' events per second. This mean that initRequest function is called quite often. Each time request object is created in memory, and function onSuccess is bind to its 'success' event.

I assumed (but here I may be wrong), that as far as there is listener (onSuccess in this case) bind to this object it cannot be garbage collected. Then I thought, memory usage will grow since memory won't be free-ed up.

As a solution for this potential leak I wanted to use .once instead of .on, as this will unbind listener and object could be garbage collected.

I've used pmap to test both scenarios (comparing .on and .once and one another scenario that is not worth to mention here), and I haven't found a big difference.

enter image description here

To sum up I have 2 questions:

  1. Is this normal GC behavior to clean memory in some intervals, or after it reach some threshold instead of continuous cleaning?

  2. Am I correctly assume that example code with .on should leak memory, which I don't see on memory consumption graph?

3
  • 1
    Some thoughts... For the first question, yes it is normal. Garbage collection runs in cycles. When you no longer have references to some memory, it can be garbage collected, but there is no indication when that will happen. As for the second question, i would expect a memory leak there as well. Curios to see an answer why it is not visible in the chart. Commented Jan 16, 2014 at 13:42
  • For clarity, could you show the code with .once? I'm assuming you did it on the redisClient, but it's just guessing at the moment. Also, I do see a little higher usage in 1. The red line.. is that the 'leak'? A legenda would be nice. Since onSuccess is shared between all the initRequests, extremely little extra memory will be used, so if your requests all finish before they reach a few million, I wouldn't expect a much higher peak. Commented Feb 24, 2014 at 13:01
  • Which redis client module did you use? I searched for RequestObject and got nothing interesting. Commented Feb 25, 2014 at 2:49

2 Answers 2

5

1: yes :-)

2: In general the leaking of memory when using event listeners is that the object that is listening is prevented from being garbage collected because the object that is emitting is keeping a reference to it.

So in your code the onSuccess function will be referenced by your request object. However, that onSuccess is only one function that is being reused as a listener for all request objects so that should not lead to memory buildup.

Sidenote: I don't know the innards of redisClient and RequestObject but to me it also looks like the request will be ready for garbage collection as soon as the initRequest function completes, that is possibly before any of its listeners are called.

Sign up to request clarification or add additional context in comments.

1 Comment

It seems that my concers came from wrong assumptions regarding who is referencing who. Now I understand that event emmiter is referencing listener and not in opposit way.
2

As far as i can see the request object should only exists within the initRequest function, and should therefor be marked for garbage collection when the function terminates.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.