bigmac
bigmac

Reputation: 717

confusion about garbage collection among closures

I've been uncertain about the rules of JS garbage collection around a closure for a while, so I figure I might as well ask... Here's a good example that I'm curious about involving jQuery's $.each method:

storeSelection: function() {
    var enabledIds = {};

    $.each(this.nodes, function(index, node) {
        if (node.enabled) {
            enabledIds[ node.id ] = true;
        }
    });

    this.selection = enabledIds;
}

The above snippit is, of course, part of an object literal. So, I've created a new object at the top of the outer function which will store the IDs of enabled items within an array. Using jQuery's .each() method, I'm looping through the array of items and logging enabled IDs. Finally, I store the selection as a member of the parent object.

My question involves that inner function which references the enabledIds object from the outer scope. Since enabledIds will be sticking around, does that prevent the inner function from being collected? I would assume not, because it's just a variable that gets cleared at the end of the inner function, right? To become a leak, I assume the inner function would need to make a hard reference to the outer object, as in:

$.each(this.nodes, function(index, node) {
    this.badIdea = enabledIds;
    if (node.enabled) {
        enabledIds[ node.id ] = true;
    }
});

However... I'm always foggy on this rule. Any help clearing up this confusion would be appreciated!

Upvotes: 2

Views: 86

Answers (2)

Alexey Lebedev
Alexey Lebedev

Reputation: 12197

You're right, the variables from the inner function (index, node) will be garbage-collected, because they can't be accessed anymore.

In this example, can you access bigstr?

a = function() {
        var bigstr = new Array(1000000).join('x');
        return function() { return bigstr; };
    }();

Yes, you can: a(), so it's not collected. What about this example:

a = function() {
        var bigstr = new Array(1000000).join('x');
        return function(n) { return eval(n); };
    }();

Again, you can: a('bigstr').

But what about this one:

a = function() {
        var smallstr = 'x';
        var bigstr = new Array(1000000).join('x');
        return function(n) { return smallstr; };
    }();

You can't access it anymore, and it's a candidate for garbage collection.

Upvotes: 1

Chris Pratt
Chris Pratt

Reputation: 239440

No, even your second example wouldn't be enough to cause a leak. badIdea is attached to the individual nodes, and the $.each block would exit and be garbage collected. All modern browsers use a "mark and sweep" algorithm for javascript garbage collection, which follows associations parent to child and collects any "unreachables", i.e. anything that can't be accessed by one of these trees.

Upvotes: 3

Related Questions