Does V8 do garbage collection on individual pieces of a scope? - javascript

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

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.

Related

JavaScript Closures and variable reference

I'm reading Cameron's, HTM5 JavaScript & JQuery. In his section on JavaScript and closures he gives this example:
function f2()
{
var i = 0;
return function() {
return ++i;
};
}
When the anonymous function was defined inside function f2 it “closed” over its environment as it existed at that point of time, and kept a copy of that environment. Since the variable i was accessible when the function was declared, it is still available when the function is invoked. JavaScript has realised that the anonymous function refers to the variable i, and that this function has not been destroyed, and therefore it has not destroyed the i variable it depends on.
In this bold section where he writes "JavaScript has realised..." does this mean that when JS identifies a dependency between an enclosed variable (i.e. outside the closure) and a closure, that it retains the reference to the variable for later use, whereas if there was no dependency upon the variable it would be destroyed (garbage collected)? So var i below would be destroyed, whereas var i in the closure example above is not?
function f2()
{
var i = 0;
}
Cameron, Dane (2013-10-30). A Software Engineer Learns HTML5, JavaScript and jQuery: A guide to standards-based web applications (p. 74). Cisdal Publishing. Kindle Edition.
The short answer to your question is 'yes, that is correct' perhaps a longer example will help?
function main() {
var i = 0;
var int = setInterval(
function() {
console.log(++i);
if ( i > 9 ) {
clearInterval(int);
}
}, 100);
}
As per the example you gave, the variable i is referenced from the inner function, and is therefore kept around for as long as that inner function is in use.
In this example, int is also kept alive for the same reason, but here we also demonstrate how the GC will clean up when it can. Once i > 9 the Interval timer is cleared, meaning that there is no longer a reference to the inner function. This then also means that the variables i and int referenced by that inner function are no-longer referenced, meaning that the GC can destroy them all.

What happens with values in closure? JavaScript

I've seen a really cool explanation of closure. So in my view closure is a way to store data somewhere. Let's see examples of closure and example without closure:
Without closure:
function F1(x,y)
{
var z=5;
function F2(){
console.log('x='+x+'y='+y+'z='+z);
}
F2();
}
F1(1,2)
With closure:
function F1(x,y)
{
var z=5;
function F2(){
console.log('x='+x+'y='+y+'z='+z);
}
return F2();
}
var p=F1(1,2)
p();
I've understood that in closure when F1() finishes its work, then F1() clears connection to the store where values of F1 are kept. But F2() still keeps the reference to the store of values.
Let's see images:
Without closure:
With closure:
I would like to know what happens in memory. I have little knowledge of C# and that reference types are reason to create objects in heap for each reference type. My question is how is it possible to store values of F2() if values of F1() are already garbage collected?
I mean what happens in memory - how many are objects created?(JavaScript creates objects on the heap like C#?) or maybe JavaScript just uses stack to store values of functions?
Every time you call a function, a new activation context containing the local variables is created. If inner functions use any of those variables, the activation context is saved (in a closure) so the local variables can be accessed outside of that function.
There is only one closure created per activation context (function call). That is,
// One closure is created every time you call doSomething
// The loop in doSomething creates a single closure that is shared
// by all the divs handlers (or all the handlers point to the same function
// instance and its closure)
function doSomething(divs) {
for (var i =0; i < divs.length; i++) {
div.onclick = function() {
// Because there is only one closure, i will be the same
// for all divs
console.log('Clicked div, i is' + i);
}
}
}
// One closure here
doSomething([div1,div2,div3]);
// One closure here
doSomething([div9,div10, div11]);
The garbage collector will never garbage collect a closure that still has references to it. As an aside, this was one of the sources for memory leaks. There's often a circular reference between a closure and a DOM element, which kept IE from garbage collecting that closure because it couldn't detect that circular reference between DOM elements and regular JavaScript objects.

Clarification regrading circular reference

I don't think I quite understand this concept.
I get how having stuff that require each other leads to a infinite loop but I don't see how this happens in some examples I view
function setHandler() {
var elem = document.getElementById('id')
elem.onclick = function() {
// ...
}
}
How is this a problem? I just see a element being attached a function on click.
It says there's a reference through the outer LexicalEnvironment - but isn't this occurring once?
Thanks in advance.
How is this a problem?
It was a major problem in early versions of IE 6 as it created "memory leaks" because circular references involving DOM elements led to memory not being released when a page was unloaded, so they consumed more and more memory, making the browser less responsive. There's a good article here.
In regard to the particular pattern in the OP, the circular reference is easily avoided:
function setHandler() {
var elem = document.getElementById('id')
elem.onclick = function() {
// ...
}
// Break circular reference
elem = null;
}
JavaScript uses something called lexical scoping. Scopes
define what variables are visible in a certain context (corollary: they define what variables are no longer visible to anyone and may be garbage collected safely)
are created for every function (every time you use the keyword, a new scope is created)
can be nested (because functions can be nested)
are persisted for every function (when you call a function it is guaranteed that it can see all variables in all scopes (!) that were available when it was created)
That means:
// +- global scope
// |
function setHandler() { // |+- scope for setHandler()
// || sees: own, global
var elem = document.getElementById('id'); // ||
// ||
elem.onclick = function() { // ||+- Scope for anonymous function
// ... // ||| sees: own, setHandler, global
} // |||
} // ||
// |
Now the anonymous function you assign to onclick can see the variables elem and setHandler and everything from the global scope.
If the element is destroyed (removed from the DOM), the garbage collector considers what variables went out of scope. A less advanced garbage collector might do this by keeping a reference count for any in-memory object and clean up that object (free the memory) when the reference count reaches zero.
Now the anonymous click handler function cannot be cleaned up because it holds a reference to elem (via the scope) which in turn holds a reference to the anonymous function (via its onclick property). The reference count for both objects stays at 1 because the two refer to each other.
Note point 4 from above: Scopes are persistent, so the "lexical environment" of setHandler() is kept alive even though program execution has already left that function - because it is needed by the anonymous inner function. (This is called "closure" and is one of the cornerstones of JS.)
Modern garbage collectors can spot that situation and clean up the event handler appropriately, but notably old versions if IE misbehaved and leaked the memory.

Is this garbage collected?

I'm sure something similar has been asked before, but the sheer number of similar questions that don't answer my question force me to ask for myself.
Say you have the following code:
(function() {
"use strict";
var somearray=[1, 2, 3];
for(var i=0; i<somearray.length; i++) {
//do something
}
function loop() {
//do something repeatedly
requestAnimationFrame(loop);
}
loop();
})();
Since the variable i is defined in the same scope as a perpetual loop, does it continue to exist even if unused, waiting for the possibility that it may be used eventually? Or is JavaScript's (particularly Chrome's V8) garbage collector smart enough to determine whether it will be used or not?
I know that I can add console.log(i) to the loop somewhere and then i will continue to exist so long as it's referenced, but will it continue to exist unreferenced in a scope that continues to exist?
This not really a question about the garbage collector rather it is question about whether the closure is optimized. The closure optimizer of the execution environment might determine that the variables are not referenced (closed over) by the nested functions and then elide them from the closure environment. If that is the case, then they are candidates for collection. If the closure optimizer isn't run, or it determines i and somearray are referenced, or it cannot determine the lifetime of i and somearray, then they will not be collected as they are required by the closure environment.
A function has an implicit environment which includes all local variables in the enclosing function (and all functions enclosing it). This environment will capture any objects referenced by those variables. A closure optimizer statically analyzes the function to determine if the environment can be trimmed to elide the unreferenced variables. If the variables are elided from the environment they are candidates for collection as soon as the function invocation is concluded.
All modern JavaScript engines have a closure optimizer.
Some common things that might disable or limit the closure optimizer include being in a debug mode, using direct eval(), use of the arguments array, use of deprecated features such as caller.
As you can see, it clearly depends on what \\do something repeatedly does and in what context the code is executed in.
One way to ensure that they are not captured regardless of what \\do something repeatedly does is to ensure they are no longer in scope. An immediately executing function will do just that so changing your code to,
(function() {
"use strict";
(function() {
var somearray=[1, 2, 3];
for(var i=0; i<somearray.length; i++) {
//do something
}
})();
function loop() {
//do something repeatedly
requestAnimationFrame(loop);
}
loop();
})();
will ensure the array is not left hanging around in memory.

How JavaScript closures are garbage collected

I've logged the following Chrome bug, which has led to many serious and non-obvious memory leaks in my code:
(These results use Chrome Dev Tools' memory profiler, which runs the GC, and then takes a heap snapshot of everything not garbaged collected.)
In the code below, the someClass instance is garbage collected (good):
var someClass = function() {};
function f() {
var some = new someClass();
return function() {};
}
window.f_ = f();
But it won't be garbage collected in this case (bad):
var someClass = function() {};
function f() {
var some = new someClass();
function unreachable() { some; }
return function() {};
}
window.f_ = f();
And the corresponding screenshot:
It seems that a closure (in this case, function() {}) keeps all objects "alive" if the object is referenced by any other closure in the same context, whether or not if that closure itself is even reachable.
My question is about garbage collection of closure in other browsers (IE 9+ and Firefox). I am quite familiar with webkit's tools, such as the JavaScript heap profiler, but I know little of other browsers' tools, so I haven't been able to test this.
In which of these three cases will IE9+ and Firefox garbage collect the someClass instance?
As far as I can tell, this is not a bug but the expected behavior.
From Mozilla's Memory management page: "As of 2012, all modern browsers ship a mark-and-sweep garbage-collector." "Limitation: objects need to be made explicitly unreachable".
In your examples where it fails some is still reachable in the closure. I tried two ways to make it unreachable and both work. Either you set some=null when you don't need it anymore, or you set window.f_ = null; and it will be gone.
Update
I have tried it in Chrome 30, FF25, Opera 12 and IE10 on Windows.
The standard doesn't say anything about garbage collection, but gives some clues of what should happen.
Section 13 Function definition, step 4: "Let closure be the result of creating a new Function object as specified in 13.2"
Section 13.2 "a Lexical Environment specified by Scope" (scope = closure)
Section 10.2 Lexical Environments:
"The outer reference of a (inner) Lexical Environment is a reference to the Lexical Environment that logically
surrounds the inner Lexical Environment.
An outer Lexical Environment may, of course, have its own outer
Lexical Environment. A Lexical Environment may serve as the outer environment for multiple inner Lexical
Environments. For example, if a Function Declaration contains two nested Function Declarations then the Lexical
Environments of each of the nested functions will have as their outer Lexical Environment the Lexical
Environment of the current execution of the surrounding function."
So, a function will have access to the environment of the parent.
So, some should be available in the closure of the returning function.
Then why isn't it always available?
It seems that Chrome and FF is smart enough to eliminate the variable in some cases, but in both Opera and IE the some variable is available in the closure (NB: to view this set a breakpoint on return null and check the debugger).
The GC could be improved to detect if some is used or not in the functions, but it will be complicated.
A bad example:
var someClass = function() {};
function f() {
var some = new someClass();
return function(code) {
console.log(eval(code));
};
}
window.f_ = f();
window.f_('some');
In example above the GC has no way of knowing if the variable is used or not (code tested and works in Chrome30, FF25, Opera 12 and IE10).
The memory is released if the reference to the object is broken by assigning another value to window.f_.
In my opinion this isn't a bug.
I tested this in IE9+ and Firefox.
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
}
var a = [];
var interval = setInterval(function() {
var len = a.push(f());
if(len >= 500) {
clearInterval(interval);
}
}, 10);
Live site here.
I hoped to wind up with an array of 500 function() {}'s, using minimal memory.
Unfortunately, that was not the case. Each empty function holds on to an (forever unreachable, but not GC'ed) array of a million numbers.
Chrome eventually halts and dies, Firefox finishes the whole thing after using nearly 4GB of RAM, and IE grows asymptotically slower until it shows "Out of memory".
Removing either one of the commented lines fixes everything.
It seems that all three of these browsers (Chrome, Firefox, and IE) keep an environment record per context, not per closure. Boris hypothesizes the reason behind this decision is performance, and that seems likely, though I'm not sure how performant it can be called in light of the above experiment.
If a need a closure referencing some (granted I didn't use it here, but imagine I did), if instead of
function g() { some; }
I use
var g = (function(some) { return function() { some; }; )(some);
it will fix the memory problems by moving the closure to a different context than my other function.
This will make my life much more tedious.
P.S. Out of curiousity, I tried this in Java (using its ability to define classes inside of functions). GC works as I had originally hoped for Javascript.
Heuristics vary, but a common way to implement this sort of thing is to create an environment record for each call to f() in your case, and only store the locals of f that are actually closed over (by some closure) in that environment record. Then any closure created in the call to f keeps alive the environment record. I believe this is how Firefox implements closures, at least.
This has the benefits of fast access to closed-over variables and simplicity of implementation. It has the drawback of the observed effect, where a short-lived closure closing over some variable causes it to be kept alive by long-lived closures.
One could try creating multiple environment records for different closures, depending on what they actually close over, but that can get very complicated very quickly and can cause performance and memory problems of its own...
Maintain State between function calls
Let’s say you have function add() and you would like it to add all the values passed to it in several calls and return the sum.
like
add(5); // returns 5
add(20); // returns 25 (5+20)
add(3); // returns 28 (25 + 3)
two way you can do this first is normal define a global variable
Of course, you can use a global variable in order to hold the total. But keep in mind that this dude will eat you alive if you (ab)use globals.
now latest way using closure with out define global variable
(function(){
var addFn = function addFn(){
var total = 0;
return function(val){
total += val;
return total;
}
};
var add = addFn();
console.log(add(5));
console.log(add(20));
console.log(add(3));
}());
function Country(){
console.log("makesure country call");
return function State(){
var totalstate = 0;
if(totalstate==0){
console.log("makesure statecall");
return function(val){
totalstate += val;
console.log("hello:"+totalstate);
return totalstate;
}
}else{
console.log("hey:"+totalstate);
}
};
};
var CA=Country();
var ST=CA();
ST(5); //we have add 5 state
ST(6); //after few year we requare have add new 6 state so total now 11
ST(4); // 15
var CB=Country();
var STB=CB();
STB(5); //5
STB(8); //13
STB(3); //16
var CX=Country;
var d=Country();
console.log(CX); //store as copy of country in CA
console.log(d); //store as return in country function in d
(function(){
function addFn(){
var total = 0;
if(total==0){
return function(val){
total += val;
console.log("hello:"+total);
return total+9;
}
}else{
console.log("hey:"+total);
}
};
var add = addFn();
console.log(add);
var r= add(5); //5
console.log("r:"+r); //14
var r= add(20); //25
console.log("r:"+r); //34
var r= add(10); //35
console.log("r:"+r); //44
var addB = addFn();
var r= addB(6); //6
var r= addB(4); //10
var r= addB(19); //29
}());

Categories

Resources