Hacker News new | ask | show | jobs
by pfraze 4596 days ago
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...

4 comments

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.

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.
Good find with the meteor.com link! It covers several memory leaks; the last example is the one that is relevant.
The mereor permalink didn't work for me, but it's in the list of articles further down the page.
Thank you!