

How JavaScript closures are garbage collected - rohshall
http://stackoverflow.com/questions/19798803/how-javascript-closures-are-garbage-collected?newsletter=1&nlcode=91287%7caea8

======
pfraze
I'm fairly sure the issue being illustrated here is due to an optimization in
how closure scopes are created, which I don't think any of the answers mention
(yet). Can't remember where I saw this, but there's a blog-post somewhere in
the wild that explains. Slap me if I'm wrong.

    
    
      // scope 1
      var someClass = function() {};
    
      function f() {
        // scope 1, 2
        var some = new someClass();
        function unreachable() { some; /* scope 1, 2, 3 */ }
        return function() { /* scope 1, 2, 4 */ };
      }
    
      window.f_ = f();
    

Basically, any closures created within scope 2 will share the same parent
scope in its scope chain rather than each closure having its own parent. That
means any variable in scope 2 that's captured by a child closure (3 or 4) will
be included in the other child scopes.

In this case, `some` is captured in `unreachable()`, thus it's going to be
included in the returned function as well. The returned function is then
retained with `window.f_`, and that's the leak.

EDIT: for clarity. EDIT2: not the original article I read, but this does cover
it: [http://www.meteor.com/blog/2013/08/13/an-interesting-kind-
of...](http://www.meteor.com/blog/2013/08/13/an-interesting-kind-of-
javascript-memory-leak)

~~~
robmcm
The bit that helped most from the meteor post was this:

 _Well, the typical way that closures are implemented is that every function
object has a link to a dictionary-style object representing its lexical scope.
If both functions defined inside replaceThing actually used originalThing, it
would be important that they both get the same object, even if originalThing
gets assigned to over and over, so both functions share the same lexical
environment._

~~~
paulddraper
Good quote. That is certainly a simple way to manage things. It isn't the only
way (nor the best IMHO), but it is the simplest.

------
i_s
The author wrote a really short code snippet that demonstrates the problem:

    
    
      function f() {
        var some = [];
        while(some.length < 1e6) {
          some.push(some.length);
        }
        function g() { some; } //removing this fixes a massive memory leak
        return function() {};    //or removing this
      }
    

If you keep a reference to the results of calling this function, it will keep
a reference to the "some" variable, even though it is not needed.

He created a page that demonstrates the problem here:

[https://s3.amazonaws.com/chromebugs/memory.html](https://s3.amazonaws.com/chromebugs/memory.html)

~~~
e12e
So well that it crashed/froze icweasel...

------
paulddraper
Unfortunately, this behavior is common across all major browsers. There is a
Chromium bug for it ([http://crbug.com/315190](http://crbug.com/315190)), but
no responses as of yet.

~~~
robmcm
This isn't going to be trivial to fix, it would require the vm to provide a
different taylored scope to each function.

~~~
paulddraper
Unfortunately, you are right. I am optimistic, however.

IE used to not GC cyclical JS/DOM references. Google Chrome is doing a massive
rework of DOM garbage collection with Oilpan.

You are right that it is not a trivial change, but there is nothing
technically infeasible about GC'ing per closure. I think it is worth it, just
as it was worth it for IE to have smarter GC.

------
martin-adams
Maybe it's being kept in case the returned function executes an eval statement
which needs the closure ;)

------
talles
Ah gc... always behaving as something alive

good question by the way

