4

I'm interested in whether V8 does garbage collection on the contents of individual variables within a scope or whether it only does garbage collection on the entire scope?

So, if I have this code:

function run() {
    "use strict";
    var someBigVar = whatever;
    var cnt = 0;

    var interval = setInterval(function() {
        ++cnt;
        // do some recurring action
        // interval just keeps going
        // no reference to someBigVar in here
    }, 1000);

    someBigVar = somethingElse;
}

run();

Will V8 garbage collect someBigVar? The closure in run() remains alive because of the setInterval() callback and obviously the cnt variable is still being used so the whole scope of run() cannot be garbage collected. But, there is no actual ongoing reference to someBigVar.

Does V8 only garbage collect an entire scope at a time? So, the scope of run() can't be garbage collected until the interval is stopped? Or is it smart enough to garbage collect someBigVar because it can see that there is no code in the interval callback that actually references someBigVar?

FYI, here's an interesting overview article on V8 garbage collection (it does not address this specific question).

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • possible duplicate of [garbage collection with node.js](http://stackoverflow.com/questions/5326300/garbage-collection-with-node-js) – Bergi Feb 26 '17 at 23:54

1 Answers1

2

Yes, it does. Only variables that are actually used inside of a closure are retained. Otherwise closure had to capture EVERYTHING that is defined in the outer scope, which could be a lot.

The only exception is if you use eval inside of a closure. Since there is no way to statically determine, what is referenced by the argument of eval, engines have to retain everything.

Here is a simple experiment to demonstrate this behaviour using weak module (run with --expose-gc flag):

var weak = require('weak');
var obj = { val: 42 };

var ref = weak(obj, function() {
  console.log('gc');
});

setInterval(function() {
  // obj.val;
  gc();
}, 100)

If there is no reference to ref inside of the closure you will see gc printed.

vkurchatkin
  • 13,364
  • 2
  • 47
  • 55
  • When I enter my debugger, there are often times when a variable I'd like to see from the outside scope is simply inaccessible. It only happens for variables that never left their function level. So, that lends credence to this answer. – Katana314 Apr 24 '15 at 20:37
  • 1
    Can you provide any reference sources for this? – jfriend00 Apr 24 '15 at 20:38
  • This example doesn't need a specific call to `gc()` does it? Do you have any other references besides your own test data? – jfriend00 Apr 24 '15 at 22:42
  • Your example is misleading, since all its variables are declared in the global scope. Global 'var' bindings become properties on the global object, so (a) they are always retained, (b) they never need to be captured by a closure. You need to wrap the code into a function. – Andreas Rossberg Apr 25 '15 at 07:23
  • This example is for node.js/io.js, so the module code is wrapped already – vkurchatkin Apr 25 '15 at 12:10