When is javascript code considered garbage for the GC - javascript

So i've been getting into the more advanced parts of javascript. Right now im learning about memory, memory leaks and garbage collecting. Many examples on the web just exaplain what the garbage collector is , but i am having trouble finding one that tells me when the code is considered garbage for the garbage collector.
So far I've read "When there's no longer a reference pointing to an object". Is that the only case? What exactly do they mean by that.
Thanks in advance.

It's better to see it as code being reachable or not from the roots, and roots are values that are inherently always reachable, such as global variables. The garbage collector in JS uses a "mark and sweep" algorithm, where it starts from the roots and visits each reference and their references and so on. Once it's visited, it gets marked as being visited/reachable together with all reachable references from there, and will not be visited again.
You can have references pointing to objects, which maybe also have references to other objects, but once they can never be reached anymore from the root, they form a sort of unreachable island of references. They will never get visited and will finally be sweeped away by the garbage collector.
There are also several optimizations done. For example some objects get created and do their job once and then die off. Those new ones get cleaned up very aggressively and fast. If they are used for longer periods of time they will be considered old, and will be visited less often to check if they should be garbage collected.

Related

'marking' an object for garbage collection in NodeJS

I'm working with some code in NodeJS, and some objects (i.e, 'events') will be medium-lived, and then discarded.
I don't want them becoming a memory burden when I stop using them, and I want to know if there is a way to mark an object to be garbage-collected by the V8 engine. (or better yet- completely destroy the object on command)
I understand that garbage collection is automatic, but since these objects will, 60% of the time, outlive the young generation, I would like to make sure there is a way they don't camp out in the old-generation for a while after they are discarded, while avoiding the inefficiency of searching the entire thing.
I've looked around, and so far can't find anything in the NodeJS docs. I have two main questions:
Would this even be that good? Would it be worth it to be able to 'mark' large amounts of unused objects to be gc'ed? (possibly 100+ at a time)
Is there even a way to do this?
Anything (speculation, hints, articles) would be appreciated. Thanks!
(V8 developer here.) There's no way to do this, and you don't need to worry about it. Marking works the other way round: the GC finds and marks live objects. Dead objects are never marked, and there's no explicit act of destroying them. The GC never even looks at dead objects. Which also means that dead objects are not a burden.
"Garbage collector" really is a misleading term: it doesn't actually find or collect garbage; instead it finds non-garbage and keeps it, and everything it hasn't found it just ignores by assuming that the respective memory regions are free.
In theory, there could be a way to manually add (the memory previously occupied by) objects to the "free list"; but there's a fundamental problem with that: part of the point of automatic memory management is that automating it provides better security and stability than relying on manual memory management (with programmers being humans, and humans making mistakes). That means that by design, a GC can't trust anyone else to declare objects as unreachable; it would always insist on verifying that claim -- which is equivalent to disregarding it, as the only way to verify it is to run a full regular GC cycle.

Experimenting with auto-removed items from WeakSet/WeakMap (via garbage collection) in Node.js when .size doesn't exist?

#1. Workaround for lack of .size property?
In JavaScript, I've never used either WeakSet or WeakMap before, and I don't know that much about garbage collection in general (I'm a PHP + JS developer, so this is the first time I've really needed to think about garbage collection). But I think I have a good use case for WeakMap right now. So I'd like to at least start experimenting with it.
The main thing I want to confirm in my experiments is the automatic removal of objects when they've been garbage collected. This would be easy to test if I could just access a WeakSet.size / WeakMap.size property on the instances to check their size, but they don't exist on the "weak" versions.
If possible, I'm guessing that the results could vary seeing that the size is going to depend on whether the garbage collector has run yet. But that's ok, as none of this experimentation code will be used in production... I just want to confirm that I actually understand how garbage collection and WeakSet/WeakMap are working. The idea of using this feature without being able to test (and therefore fully understand) it makes me very uneasy, and I'm concerned that I'll end up finding out about memory leaks when its too late (in production).
Are there any workarounds or alternatives to deal with the lack of WeakSet.size and WeakMap.size... at least just for debugging/testing/learning purposes?
If not a .size workaround, is there maybe a way to check the memory usage of my WeakMap collection instances? That would be just as useful, as that's where the main concern is.
The only thing I can think of right now is checking the memory of the entire Node.js process... which doesn't seem very reliable to me.
#2. What is .length for?
Also I'm a bit confused about why there is a .length property on the class constructor/instance prototype of both WeakSet and WeakMap (not on your instances of them).
According to:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakSet
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WeakMap
...both pages say that .length is:
The value of the length property is 0.
Are they literally just hard-coded to the number 0 at all times? What's the point of that?
Searching for either "WeakSet.length" or "WeakMap.length" on Google (including the double quotes for exact results) yields no further information, only about 20 results for each, which are just mirrors of the MDN pages.
The size won't be available for either WeakSet or WeakMap since their keys are just references to objects, and these are handled by the Garbage Collector. Since the collector cannot be manually controlled (or shouldn't be), it will free the memory of these objects, once they are no longer referenced, at any point during runtime. The workaround you suggest to implement a way to see its current size would not be effective nor recommended considering this.
The length is there since both WeakSet and WeakMap are created through their prototype counterparts. Given how the collector will take care of clearing the object reference at any point,
As for experiment with them, you can try them out in Chrome and expose the garbage collector (and manually calling it) to see how the WeakMap clears itself after an object reference is lost (explained in this answer). Otherwise, you may still see the reference within the WeakMap or WeakSet since devtools usually prevents the garbage collector from running.

Are WebGL objects garbage collected?

In JavaScript memory that I allocated (e.g. an ArrayBuffer) gets freed up when I don't have any reference to it anymore by the GC as I understood that right?
WebGL objects like Buffers or Textures are associated with a memory block on the GPU as allocated by gl.bufferData() or gl.textureImage2D().
I'm wondering: if I give up my last reference to a WebGLTexture or WebGLBuffer object, does it get garbage collected with its GPU memory block freed by the JavaScript VM automatically?
Yes
From spec
Note that underlying GL object will be automatically marked for deletion when the JS object is destroyed
But you should notice that the object would probably not destroyed at the time you give up the last reference, so it's still a good practice to call deleteBuffer.
Copied from this answer: Are WebGLTextures garbage collected?
with the word WebGLTexture changed to WebGLObject
Yes and no.
Yes they are garbage collected. But garbage collection happens whenever the browser decides to collect them. From the POV of most browser JavaScript engines the WebGLObject object is a tiny object that just contains an int so it has no easy way to know of any special pressure to collect it. In other words when the GPU runs out of memory the JavaScript garbage collector, which has no connection to the GPU, has no way of knowing that it needs to free these tiny WebGLObject objects in order to free up texture memory. It's only looking at CPU memory.
This is actually a well known problem of garbage collection. It's great for memory. It's not so great for other resources.
So, yes, WebGLObject objects are garbage collected and yes the texture/buffer/renderbuffer/program/shader will be freed but practically speaking you need to delete them yourself if you don't want to run out of memory.
Of course the browser will free them all if you refresh the page or visit a new page in the same tab but you can't count on the browser to garbage collect WebGLObject objects (textures/buffers/renderbuffers/programs/shaders) in any useful way.

Are global variables cleaned by garbage collector in Node?

In the following JS code, will example1 or example2 be ever cleaned by the garbage collector? Will their memory be ever released by the GC? I am dealing with memory leaks and I have a few such instances in my code.
example1 = 'Outside a function'
function sample(x){
example2 = 'Inside a function'
}
sample(1)
From what I understand is neither of the variables will ever be cleaned by Garbage collector because they are treated as global variables. Might sound like a trivial question but finding memory leaks is like finding a needle in a haystack
The heap has two main segments, the New Space and the Old Space. The New Space is where new allocations are happening; it is fast to collect garbage here and has a size of ~1-8MBs. Objects living in the New Space are called Young Generation. The Old Space where the objects that survived the collector in the New Space are promoted into - they are called the Old Generation. Allocation in the Old Space is fast, however collection is expensive so it is infrequently performed .
You need understand few thinks, like:
1 - The garbage collector builds a list of "roots". Roots usually are global variables to which a reference is kept in code. In JavaScript, the "window" object is an example of a global variable that can act as a root. The window object is always present, so the garbage collector can consider it and all of its children to be always present (i.e. not garbage).
2 - All roots are inspected and marked as active (i.e. not garbage). All children are inspected recursively as well. Everything that can be reached from a root is not considered garbage.
3- All pieces of memory not marked as active can now be considered garbage. The collector can now free that memory and return it to the OS.
So about your questions:
From what I understand is neither of the variables will ever be cleaned by Garbage collector because they are treated as global variables.
Might sound like a trivial question but finding memory leaks is like finding a needle in a haystack
You are correct.

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;

Categories

Resources