[ACCEPTED]-garbage collection with node.js-v8

Accepted answer
Score: 72

Simple answer: if value of the str is not referenced 31 from anywhere else (and str itself is not referenced 30 from restofprogram) it will become unreachable as soon 29 as the function (str) { ... } returns.

Details: V8 compiler distinguishes 28 real local variables from so called context variables 27 captured by a closure, shadowed by a with-statement 26 or an eval invocation.

Local variables live 25 on the stack and disappear as soon as function 24 execution completes.

Context variables live 23 in a heap allocated context structure. They 22 disappear when the context structure dies. Important 21 thing to note here is that context variables 20 from the same scope live in the same structure. Let 19 me illustrate it with an example code:

function outer () {
  var x; // real local variable
  var y; // context variable, referenced by inner1
  var z; // context variable, referenced by inner2

  function inner1 () {
    // references context 
    use(y);
  }

  function inner2 () {
    // references context 
    use(z);
  }

  function inner3 () { /* I am empty but I still capture context implicitly */ } 

  return [inner1, inner2, inner3];
}

In 18 this example variable x will disappear as 17 soon as outer returns but variables y and z will 16 disappear only when both inner1, inner2 and inner3 die. This happens 15 because y and z are allocated in the same 14 context structure and all three closures 13 implicitly reference this context structure 12 (even inner3 which does not use it explicitly).

Situation 11 gets even more complicated when you start 10 using with-statement, try/catch-statement which on V8 9 contains an implicit with-statement inside catch 8 clause or global eval.

function complication () {
  var x; // context variable

  function inner () { /* I am empty but I still capture context implicitly */ }

  try { } catch (e) { /* contains implicit with-statement */ }

  return inner;
}

In this example x will 7 disappear only when inner dies. Because:

  • try/catch-contains implicit with-statement in catch clause
  • V8 assumes that any with-statement shadows all the locals

This 6 forces x to become a context variable and 5 inner captures the context so x exists until inner dies.

In 4 general if you want to be sure that given 3 variable does not retain some object for 2 longer than really needed you can easily 1 destroy this link by assigning null to that variable.

Score: 4

Actually your example is somewhat tricky. Was 54 it on purpose? You seem to be masking the outer 53 val variable with an inner lexically scoped 52 restofprogram()'s val argument, instead of 51 actually using it. But anyway, you're asking 50 about str so let me ignore the trickiness of 49 val in your example just for the sake of simplicity.

My 48 guess would be that the str variable won't 47 get collected before the restofprogram() function 46 finishes, even if it doesn't use it. If the 45 restofprogram() doesn't use str and it doesn't 44 use eval() and new Function() then it could be safely collected but 43 I doubt it would. This would be a tricky 42 optimization for V8 probably not worth the 41 trouble. If there was no eval and new Function() in the language 40 then it would be much easier.

Now, it doesn't 39 have to mean that it would never get collected 38 because any event handler in a single-threaded 37 event loop should finish almost instantly. Otherwise 36 your whole process would be blocked and 35 you'd have bigger problems than one useless 34 variable in memory.

Now I wonder if you didn't 33 mean something else than what you actually 32 wrote in your example. The whole program 31 in Node is just like in the browser – it 30 just registers event callbacks that are 29 fired asynchronously later after the main 28 program body has already finished. Also 27 none of the handlers are blocking so no 26 function is actually taking any noticeable 25 time to finish. I'm not sure if I understood 24 what you actually meant in your question 23 but I hope that what I've written will be 22 helpful to understand how it all works.

Update:

After 21 reading more info in the comments on how 20 your program looks like I can say more.

If 19 your program is something like:

readfile("blah", function (str) {
  var val = getvaluefromstr(str);
  // do something with val
  Server.start(function (request) {
    // do something
  });
});

Then you 18 can also write it like this:

readfile("blah", function (str) {
  var val = getvaluefromstr(str);
  // do something with val
  Server.start(serverCallback);
});
function serverCallback(request) {
  // do something
});

It will make 17 the str go out of scope after Server.start() is 16 called and will eventually get collected. Also, it 15 will make your indentation more manageable 14 which is not to be underestimated for more 13 complex programs.

As for the val you might make 12 it a global variable in this case which 11 would greatly simplify your code. Of course 10 you don't have to, you can wrestle with 9 closures, but in this case making val global 8 or making it live in an outer scope common 7 for both the readfile callback and for the 6 serverCallback function seems like the most 5 straightforward solution.

Remember that everywhere 4 when you can use an anonymous function you 3 can also use a named function, and with 2 those you can choose in which scope do you 1 want them to live.

Score: 1

My guess is that str will NOT be garbage 7 collected because it can be used by restofprogram(). Yes, and 6 str should get GCed if restofprogram was 5 declared outside, except, if you do something 4 like this:

function restofprogram(val) { ... }

readfile("blah", function(str) {
  var val = getvaluefromstr(str);
  restofprogram(val, str);
});

Or if getvaluefromstr is declared 3 as something like this:

function getvaluefromstr(str) {
  return {
    orig: str, 
    some_funky_stuff: 23
  };
}

Follow-up-question: Does 2 v8 do just plain'ol GC or does it do a combination 1 of GC and ref. counting (like python?)

More Related questions