Lifetime of JavaScript variables - javascript

What is the lifetime of a variable in JavaScript, declared with "var".
I am sure, it is definitely not according to expectation.
<script>
function(){
var a;
var fun=function(){
// a is accessed and modified
}
}();
</script>
Here how and when does JavaScript garbage collect the variable a? Since a is a part of the closure of the inner function, it ideally should never get garbage collected, since the inner function fun, may be passed as a reference to an external context. So fun should still be able to access a from the external context.
If my understanding is correct, how does garbage collection happen then, and how does it ensure to have enough memory space, since keeping all variables in memory until the execution of the program might not be tenable ?

The ECMAScript specification does not specify how the garbage collector should work, it only says that if an identifier is reachable (through a direct pointer or a closure), it shouldn't be GCed.
Check out this article about identifier resolution, closures, scope chaining and garbage collection in ECMAScript.
Hope it helps

'a' will not be garbage-collected as long as there are external references to 'fun'. The browser ensures it has enough memory by asking for more memory from the OS.

Related

Does a Javascript closure retain the entire parent lexical environment or only the subset of values the closure references? [duplicate]

This question already has answers here:
About closure, LexicalEnvironment and GC
(3 answers)
Closed 3 years ago.
Consider the following example:
function makeFunction() {
let x = 3;
let s = "giant string, 100 MB in size";
return () => { console.log(x); };
}
// Are both x and s held in memory here
// or only x, because only x was referred to by the closure returned
// from makeFunction?
let made = makeFunction();
// Suppose there are no further usages of makeFunction after this point
// Let's assume there's a thorough GC run here
// Is s from makeFunction still around here, even though made doesn't use it?
made();
So if I close around just one variable from a parent lexical environment, is that variable kept around or is every sibling variable in its lexical environment also kept around?
Also, what if makeFunction was itself nested inside another outer function, would that outer lexical environment be retained even though neither makeFunction nor makeFunction's return value referred to anything in that outer lexical environment?
I'm asking for performance reasons - do closures keep a bunch of stuff around or only what they directly refer to? This impacts memory usage and also resource usage (e.g. open connections, handles, etc.).
This would be mostly in a NodeJS context, but could also apply in the browser.
V8 developer here. This is a bit complicated ;-)
The short answer is: closures only keep around what they need.
So in your example, after makeFunction has run, the string referred to by s will be eligible for garbage collection. Due to how garbage collection works, it's impossible to predict when exactly it'll be freed; "at the next garbage collection cycle". Whether makeFunction runs again doesn't matter; if it does run again, a new string will be allocated (assuming it was dynamically computed; if it's a literal in the source then it's cached). Whether made has already run or will run again doesn't matter either; what matters is that you have a variable referring to it so you could run it (again). Engines generally can't predict which functions will or won't be executed in the future.
The longer answer is that there are some footnotes. For one thing, as comments already pointed out, if your closure uses eval, then everything has to be kept around, because whatever source snippet is eval'ed could refer to any variable. (What one comment mentioned about global variables that could be referring to eval is not true though; there is a semantic difference for "global eval", a.k.a. "indirect eval": it cannot see local variables. Which is usually considered an advantage for both performance and debuggability -- but even better is to not use eval at all.)
The other footnote is that somewhat unfortunately, the tracking is not as fine-grained as it could be: each closure will keep around what any closure needs. We have tried fixing this, but as it turns out finer-grained tracking causes more memory consumption (for metadata) and CPU consumption (for doing the work) and is therefore usually not worth it for real code (although it can have massive impact on artificial tests stressing precisely this scenario). To give an example:
function makeFunction() {
let x = 3;
let s = "giant string, 100 MB in size";
let short_lived = function() { console.log(s.length); }
// short_lived(); // Call this or don't, doesn't matter.
return function long_lived() { console.log(x); };
}
let long_lived = makeFunction();
With this modified example, even though long_lived only uses x, short_lived does use s (even if it's never called!), and there is only one bucket for "local variables from makeFunction that are needed by some closure", so that bucket keeps both x and s alive. But as I said earlier: real code rarely runs into this issue, so this is usually not something you have to worry about.
Side note:
and also resource usage (e.g. open connections, handles, etc.)
As a very general statement (i.e., in any language or runtime environment, regardless of closures or whatnot), it's usually advisable not to rely on garbage collection for resource management. I recommend to free your resources manually and explicitly as soon as it is appropriate to free them.

Do variables declared inside callback functions remain in memory or are they destroyed upon end of callback execution?

I have this code snippet; It basically connects to mongo database and goes through documents. On each iteration it searches for messages array of objects. It creates variable of messages, and then loops through it. Does declared variable (var msg) inside callback function remain in memory or is it destroyed upon end of callback function execution? Would there be any difference if var msg was actually declared as let msg? Is there a way to discard whole scope from the memory?
MongoClient.connect(mongoUrl, (err, db) => {
assert.equal(null,err);
var collection_data = db.collection('threadContents').find();
collection_data.on('data', (doc) => {
var msg = doc.messages;
for (var variable in msg) {
console.log(msg);
}//forin(msg)
});//collection_data.on
});//mongo.connect
In theory - yes.
In practice - it's not that simple...
In your example, var msg does not "leak" outside of it's original scope, so it will most likely get destroyed when callback finishes it's job.
One thing to note - the destruction of this object doesn't have to happen immediately - JS Engines are mostly Garbage Collected, so this piece of memory can stay on the stack for some time, but it won't be reachable anymore.
If you would declare this variable in outer scope, it could possibly stay in the memory if that scope stayed in memory (so, other pieces of code could access that variable). You can read about this behavior in Closures section at MDN.
Another thing to note is usage of console.log. In general, non-primitive values (like Objects or Arrays, which actually are "special" objects), will be accessible by reference, not by value. Therefore, if your var msg is a non-primitive, it will most likely persist in the memory until you clear your console. Primitive values would be copied, so strictly speaking they would still persist in the memory, but probably in another place in the memory (although JIT engines could probably try to optimize that and don't copy the memory if it's not necessary).
Node.js (and all javascript engines) rely on tracing garbage collection, which means that allocated memory is deallocated in a non-deterministic way, i.e. you cannot predict exactly when it will happen. This usually does not affect you, but uif you really want some chunk of memory or some other resource to be deallocated in a predictable way, you have to use some ad-hoc technique.
In your specific example 'msg' will be deleted, but don't expect it to be deleted straight away.

What methods are there to prevent the Javascript gc from running as little as possible?

I'm learning Javascript, and in the various texts the authors will speak of javascript using a mark and sweep gc to deallocate objects from memory. They will also speak of how if you set the value a variable references to null it will delete the reference to that value, allowing the allocated space to be set for gc. This SO answer says that you can remove the allocated memory and the reference by setting the value the variable contains to null and then to undefined, effectively removing the allocated space from the heap (if I understood it correctly).
So my question is this: Is it possible to write javascript in such a way that you can eliminate gc?
(If it is implementation specific I would like to know if it is possible on v8, though if this is possible on rhino or other js implementations that would be of immense use too)
Judging by projects like LLJS my request isn't too unreasonable, but I'm not entirely sure how the memory module does it.
I've always found it helpful if I explain why I'm asking so here it goes. I really like compilers, and I wanted to write a compile-to-js language that leveraged a static inferred typing system similar to SML. The reason why I wanted to write my own was because I wanted to utilize region inference to determine exactly when objects and variables come out of scope (as much as possible) and upon leaving scope remove it from the heap, thereby eliminating as much gc as possible. This is mostly a research project (read: because I can) so any resources on memory optimization in javascript would also be greatly appreciated!
EDIT: I guess another way to phrase it would be "Is it possible to write js in such a way that the gc will deterministically never run (as much as possible)? If so what techniques would be involved?"
I'm not looking per se for delete because that marks the element for deletion thereby invoking what I wanted to (try to) avoid, I was curious if the implementation's gc would run if I removed all references (and the value) associated with the variable.
Alternatively, paraphrasing from the referenced SO Answer:
x = foo;
x = null;
x;
Is x still on the heap?
It's not entirely clear what you're looking for.
The standard Javascript implementations have NO way of manually deallocating memory. You can remove a property with the delete operator, but that just removes the property from the object. It doesn't even free any contents that the property points to (that is left for garbage collection if there are no other references to that data).
Javascript was designed from the ground up to be a garbage collected language. It frees things from physical memory only when the garbage collector runs and that garbage collector finds objects that are unreachable (e.g. there are no references to those objects still in use). The language does not contain commands to free memory.
It is possible (in some JS implementations) to call the GC yourself rather than wait for the JS engine to run it, but it's still using GC to decide what to free.
Responding to the additional things you added to your answer.
To the best I know, javascript only cleans things up when the GC runs. Until then objects are marked such that the GC can see that there are no references to them anywhere, but they aren't actually freed until the GC checks and notices this. Further, local variables in a function scope are themselves a type of object and those are not freed until the GC runs and notices that there are no references to the function scope (in JS, a closure can maintain a reference to a function scope even after the function has completed).
So, in your code example:
x = foo; x = null; x;
x is still alive and occupying some space because it's still in scope and code could still reach it. It's contents will be null which presumably takes no extra space beyond the variable itself, but the space for the variable itself won't be freed until the function context it is in is found to be reference free by the garbage collector.
JS is a garbage collected language. That's when things are actually freed from the heap. There are no instructions in the language to free things anytime sooner.
The delete keyword will trigger garbage collection by the browser. Be aware that it deletes entire chains of objects unless you nullify object references.
var o = {...};
delete o;

Can jquery proxy be used to avoid closure memory leak?

I was reading Google's Javascript style guide regarding closure (http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml#Closures) and I wonder whether it is safe to use jquery proxy to execute a callback while not fall into the memory leak trap?
The thing to remember about closures in any managed memory environment is how the garbage collector works. It starts with root objects like "window" and follows every possible memory reference. If it can find an object, then that object can't be reclaimed.
The key is to cut all possible paths when you no longer need the closure. That includes the closure-referencing function, all objects that reference the function, and the object that owns the function. That would include any proxies; null out references to those as well.

When is the memory claimed by a Javascript object freed after last reference is deleted?

Let's say I created an big object in a scope. It is referred to by child scopes, but all of them exits gracefully. And no closure referring to it at all. After this scope exits, I suppose the last reference to the object is deleted, right? Is the memory consumed by the object freed right away, or is it only marked as free and has to wait for the garbage collector to delete it?
Garbage collection depends on the Javascript implementation. Theoretically, objects should be deleted after all references to them are gone. If you define an object in scope and nothing outside the scope references it (for example, adding it to an array outside the scope would be an outside reference), it should be collected sometime after you leave the scope.
This is a more detailed explanation.

Categories

Resources