1

When can o be garbage collected? I presume after the completion of the setTimeout callback?

var o = {
    foo() {
        setTimeout(function() {}, 10000);
    }
};

o.foo();
o = null;

And this one?

var o = {
    bar: 0
};

o.foo = function() {
    setTimeout(function() { o.bar; }, 10000);
}

o.foo(); // Sorry missed this important bit.
o = null;
T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
Ben Aston
  • 53,718
  • 65
  • 205
  • 331

2 Answers2

5

(Side note: For anyone wondering whether Ben's code is syntactically correct: Yes, it is, as of ES2015; it wouldn't be in ES5 or earlier. It's using the new "method definition" syntax ES2015 defines for object initializers.)

Re your first question, on this code:

var o = {
    foo() {
        setTimeout(function() {}, 10000);
    }
};

o.foo();
o = null;

The object initially assigned to o is eligible for GC right away, even before the timer callback, because nothing keeps a reference to it after the o = null; statement.

But there are other objects that may or may not be eligible for GC, it depends on theory (the specification) vs. practice (implementation optimizations not ruled out by the spec):

Until the timer callback occurs, the timer mechanism keeps a reference to the anonymous function, and so that anonymous function isn't eligible for GC.

In theory, the anonymous function has a reference to the environment object in which it was created, which in turn has a reference to foo, and so the anonymous function keeps both the environment and foo in memory until the timer fires, releases its reference, and the anonymous function is eligible for GC.

In practice, since the anonymous function doesn't reference foo or any arguments or local variables within foo (and doesn't use eval), a JavaScript implementation is free to optimize and allow foo and that environment object to be GC'd even though the setTimeout call still has a reference to that anonymous function. (And some do indeed do closure optimization, such as V8.) They can do that because we can't see any side-effects from it other than memory consumption or the lack thereof.


Re your additional question, on this code:

var o = {
    bar: 0,
    foo() {
        setTimeout(function() { o.bar; }, 10000);
  }
};

o.foo();
o = null;

The object itself is still eligible for GC immediately.

Re foo and the environment object for the call to it:

In theory, they're both retained (as they were above). In practice, I don't know if that affects the optimization that the engine can do around foo and the environment for the call or not. It shouldn't, because the o variable is bound to the global environment, not the one set up by the call to foo, and so the environment chain could be edited to skip the environment created by the call to foo. So engines could optimize it, and at a total guess I'd say they probably do, but I don't know that they do.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • Does `setTimeout()` call guarantee that the closure will still be there? I thought timeout closure could also be garbage collected at once, even before timeout triggers, if nothing references it. – Michael Antipin Dec 09 '15 at 08:30
  • @NoxNoctis do you refer to the "anonymous function" when you say "closure"? "if nothing references it" --- it is referenced by a timer queue. – zerkms Dec 09 '15 at 08:31
  • @T.J Crowder Sorry, I made a mistake in my original posting. Corrected now. – Ben Aston Dec 09 '15 at 08:33
  • 1
    @NoxNoctis: The timer mechanism has a reference to the anonymous function, thus preventing it from being GC'd until it releases that reference (after it fires and calls the function). As I said above, the anonymous function has an (indirect) reference to `foo`, in theory keeping `foo` in memory until the anonymous function is also eligible for GC, but in practice modern engines can optimize that reference to `foo` away. – T.J. Crowder Dec 09 '15 at 08:34
  • @T.J.Crowder I see. Is timer referencing mechanism a part of the JS standard? I'm just curious, because in actionscript1 (which is ecma 262 and all, and is copy-and-paste compatible with JS) Flash Player's avm1 GC can remove anonymous functions from the memory if they are not referenced and thus halt `setTimeout()`/`setInterval()`. This was a typical pitfall for beginners. – Michael Antipin Dec 09 '15 at 08:45
  • @RobG: That's what I said, e.g., theory (specification) vs. reality (implementation optimization). I've edited to define what I mean by theory vs. reality. – T.J. Crowder Dec 09 '15 at 08:58
  • @NoxNoctis: The specification addresses function references. The timer mechanism obviously has a reference to the function it's waiting to call. I don't know anything about ActionScript, but whether a function is anonymous or not has no bearing whatsoever on whether or when it's eligible for GC in JavaScript, other than that a function *declaration* (not expression) will create a binding to the function in the environment where the declaration occurs, thus retaining the function for as long as that environment exists. – T.J. Crowder Dec 09 '15 at 09:03
0

It differs from browser to browser, but rule of thumb is that an object is garbage collected once all of its references are either missing or null or both.

See more: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Memory_Management#Garbage_collection

Meghan
  • 1,215
  • 11
  • 17
  • 1
    "all of its references are either missing **or null**" --- the bolded part is wrong. A reference cannot be `null`, by definition. – zerkms Dec 09 '15 at 08:33