from Hacker News

How JavaScript closures are garbage collected

by rohshall on 11/12/13, 10:10 PM with 14 comments

  • by pfraze on 11/13/13, 1:22 AM

    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...

  • by i_s on 11/13/13, 1:31 AM

    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

  • by paulddraper on 11/13/13, 4:58 AM

    Unfortunately, this behavior is common across all major browsers. There is a Chromium bug for it (http://crbug.com/315190), but no responses as of yet.
  • by martin-adams on 11/13/13, 9:05 AM

    Maybe it's being kept in case the returned function executes an eval statement which needs the closure ;)
  • by talles on 11/13/13, 2:39 AM

    Ah gc... always behaving as something alive

    good question by the way