2

I've been reading up a lot on closures in Javascript. I come from a more traditional (C, C++, etc) background and understand call stacks and such, but I am having troubles with memory usage in Javascript. Here's a (simplified) test case I set up:

function updateLater(){
    console.log('timer update');

    var params = new Object();
    for(var y=0; y<1000000; y++){
        params[y] = {'test':y};
    }
}

Alternatively, I've also tried using a closure:

function updateLaterClosure(){

return (function(){

    console.log('timer update');
    var params = new Object()
    for(var y=0; y<1000000; y++)
    {
        params[y] = {'test':y};
    }
});
}

Then, I set an interval to run the function...

setInterval(updateLater, 5000); // or var c = updateLaterClosure(); setInterval(c,5000);

The first time the timer runs, the Memory Usage jumps form 50MB to 75MB (according to Chrome's Task Manager). The second time it goes above 100MB. Occasionally it drops back down a little, but never below 75MB.

Check it out yourself: https://local.phazm.com:4435/Streamified/extension/branches/lib/test.html

Clearly, params is not being fully garbage collected, because the memory from the first timer call is not being freed... yet, neither is it adding 25MB of memory on EACH call, so it is not as if the garbage collection is NEVER happening... it almost seems as though one instance of "params" is always being kept around. I've tried setting up a sub-closure and other things... no dice.

What is MOST disturbing, though, is that the memory usage trends upwards. It might "just" be 75MB for now, but leave it running for long enough (overnight) and it'll get to 500 MB.

Ideas?

Thanks!

Zane Claes
  • 14,732
  • 15
  • 74
  • 131
  • 1
    Strong suggestion: buy this book: http://www.amazon.com/JavaScript-Good-Parts-Douglas-Crockford/dp/0596517742/ – paulsm4 Apr 20 '12 at 23:19
  • 1
    And please remember: Java != Javascript. Unlike Java, each browser might have a wildly different garbage collection implementation. For example: http://javascript.crockford.com/memory/leak.html – paulsm4 Apr 20 '12 at 23:21
  • re: java vs. javascript:: of course - this isn't my first rodeo, but thanks for the reminder ;) Unfortunately I'm under a time crunch right now and don't have time to read a whole book just to get to a solution for this issue :( – Zane Claes Apr 20 '12 at 23:24
  • The Chrome memory usage you see in a system task manager is the total memory an app is using. Some of that memory may actually be reserved for future use within the app. So, just because your memory goes up once and doesn't go back down does not mean you have a leak. It could be that the pool of memory that Chrome has allocated from the system for future use is just larger. As long as it doesn't keep going up with repeated usages, it is not a leak. – jfriend00 Apr 21 '12 at 01:31
  • @jfriend00 fascinating - I guess I expected it to work more like a debugger/profiler that tells you current memory allocations. Unfortunately, it is indeed trending upwards (though in a zig-zag fashion) for me. – Zane Claes Apr 21 '12 at 02:33
  • You have a `console.log()` statement in your code. If you run that for an hour, the log might continually get bigger and bigger (consuming more memory). Remove that and retest. Also, I don't see why you're using a closure here as there is no point to it. – jfriend00 Apr 21 '12 at 03:59
  • I ran this [slightly modified jsFiddle](http://jsfiddle.net/jfriend00/bNVh9/) of your code for 7000 iterations over about 2 hrs in Chrome and saw no lasting increase in memory. – jfriend00 Apr 21 '12 at 05:49

2 Answers2

1

Allocating 25mb causes a GC to happen. This GC cleans up the last instance but of course not the current. So you always have one instance around.

GC does not happen when the program is idle. It does not happen between your timer calls so the memory stays around.

usr
  • 168,620
  • 35
  • 240
  • 369
  • Okay... is there any way to trigger manual garbage collection, then? What I'm building needs to allocate a decent chunk of memory on a timer... and it basically ends up (eventually) exploding the page. – Zane Claes Apr 20 '12 at 23:22
  • Not in JavaScript. There is no browser support for it. Actually, I don't have a recommendation for you except for allocating less. – usr Apr 20 '12 at 23:23
  • Unfortunately, allocating less is not an option. In the real scenario, I'm parsing JSON data from a server (using an AJAX command on a timer). The resultant object is not small. – Zane Claes Apr 20 '12 at 23:33
  • also... this does not explain why the memory usage would trend upwards over time. – Zane Claes Apr 20 '12 at 23:36
  • Hm I cannot repro this in chrome. I get constant ~25mb after an hour. – usr Apr 21 '12 at 00:26
1

That is not even a closure. A closure is when you return something from a function, like an array, function, object or anything that can contain references, and it carries with it all the local members of that function.

what you have there is just a case of a very long loop that is building a very big object. and maybe your memory does not get reclaimed as fast as you are building the huge objects.

Community
  • 1
  • 1
Joseph
  • 117,725
  • 30
  • 181
  • 234
  • You're right. I had originally set up a closure (with the same effects) but simplified it for the context of this question, but did not sufficiently change my vocabulary in writing it to make this evident. Regardless, neither a closure nor a normal function seems to work. – Zane Claes Apr 20 '12 at 23:29
  • can you at least post a simplified case of the structure of your closure and where it gets stored after it is returned. – Joseph Apr 20 '12 at 23:35
  • I just updated the page to use a closure instead: https://local.phazm.com:4435/Streamified/extension/branches/lib/test.html Just wanted to point out: the memory usage is trending upward over time, too (albeit slowly). – Zane Claes Apr 20 '12 at 23:37
  • can you post the code instead? if that link dies, your post will bbe senseless in the future. – Joseph Apr 20 '12 at 23:39