16

If i have a function like this

function do(callback) {
  //do stuff
  callback();
}

and then I pass in an anonymous function:

do(function() { //do something else });

does that anonymous function ever get collected during the lifespan of the page? If not, how can i make it available for GC?

do I have to do this?

var h = function() { //do something };
do(h);
delete h;

Do I even have to worry about this? I am building a web app that has a long lifespan, makes a lot of ajax calls keeps objects for a while and doesn't really require a page refresh to navigate thru. So I'm trying to figure out if I might fall into a memory leak monster.

Jose
  • 10,891
  • 19
  • 67
  • 89
  • For me, I tend to get the most amount of memory leaks from not removing event listeners to objects that I thought I had deleted. There are other JS-related memory leak posts around here http://stackoverflow.com/questions/5028479/finding-memory-leaks-in-javascript-using-firebug You might also want to look here http://stackoverflow.com/questions/864516/what-is-javascript-garbage-collection – mrk Jun 09 '11 at 17:47

2 Answers2

13

The only reference to the anonymous function is the function argument, and that disappears when the function finishes, so your callback will be available for garbage collection after that. Except when something else gets a reference to it, which can happen easily with closures:

function doo(callback) {
    $.get(url, function() {
        // callback is visible here!
    });
    callback();
}
doo(function() { /* do something else */ });

callback (along with the whole scope created by calling doo) must stay in the memory, because the inner function can reference it through the closure; it can only be garbage collected when the inner function is garbage collected, and since that function is a property of the jqXHR object, that object must be garbage collected before that, and who knows when that will happen...

Update You can avoid unnecessary closures by not defining your functions inside other functions:

var func = function() {
    // callback is not visible here
}
function doo(callback) {
    $.get(url, func);
    callback();
}
doo(function() { /* do something else */ });
Tgr
  • 27,442
  • 12
  • 81
  • 118
  • if i would do this in the `doo` function var `var g = $; g.get...` would that make callback collectable? or what could I do make your example collectable? – Jose Jun 10 '11 at 04:45
  • @Jose: referring to `$` by another name does not do anything useful. I updated my answer to show how closures can be avoided. Of course, if you can just always reuse the same arguments in your calls to `doo` instead of creating an anonymous function every time, that is a simpler way to solve the problem. – Tgr Jun 10 '11 at 09:43
  • I think you mean "var func = function()..." not "var fun" ... either that or $.get(url, func) should get updated. – Crashalot Apr 20 '12 at 01:40
  • @Crashalot: fixed, thanks. Looking back, using a deferred would have been more elegant though: `function doo() { return $.get(url).then(function () {/*...*/}); }; doo().then(function() {/* do something else */});` – Tgr Apr 20 '12 at 11:08
  • The `callback` variable will be available through closure, only if it is used explicitly, thus in the above example, `callback` will be garbage-collected. – losnir Aug 06 '15 at 11:46
  • 1
    @losnir, that depends on the JS engine. Some constructs make it impossible to tell what variables will be used (e.g. http://jsfiddle.net/x8xL8dwq/ ) - modern browsers evaluate code containing such constructs differently, older ones don't. – Tgr Aug 06 '15 at 19:18
2

Watch out for circular references, otherwise the GC for the browser will clean those up. Closures make it really easy to create a circular reference, and that might be trapped in memory even if you browse away from the page that created it. So, web applications that stay on-screen for long periods of time are especially vulnerable.

Check out the section "Memory leaks" here: https://developer.mozilla.org/en/A_re-introduction_to_JavaScript.

I've designed quite a few static-page web applications. I've found that even when you don't have to clean up objects and event handlers (ie you're sure there is no circular reference), it can't hurt. It usually only adds a couple of extra lines of code, and it keeps memory use and efficiency at the forefront of your mind as you write your code. This is something of a shift for web developers because we usually don't have to think about this kind of thing very much when creating a website.

Chris Baker
  • 49,926
  • 12
  • 96
  • 115