Take a look at this part of a Chrome heap snapshot:
It shows the retainers of an object in the heap that, as far as I know and can see, should be garbage, but is not collected despite that.
The "shortest" path to the root is, after all, a cyclical path (it never actually reaches the root). Which leaves one to wonder, how is the snapshot viewer even able to assign a distance of 12 to it? Is that just the number of steps it took through the cycle before giving up? Note how the distance never gets below 11.
I've read that it can take a few iterations to clean up subgraphs with circular references. But repeated forced collections (with the trash can button in the Timeline tab) failed to clean up these objects.
Note that exploring through the '185' references eventually leads to the same system / Context @862399
, so there really isn't a path from the root to this object (at least not visible here).
Am I going crazy, or is the garbage collector actually broken? I don't remember having this issue in the past. I'm on Chrome 45.0.2454.101. Beta 46.0.2490.64 behaves the same.
There are two garbage collectors in V8. The Major GC (Mark-Compact) collects garbage from the whole heap. The Minor GC (Scavenger) collects garbage in the young generation.
In V8, the garbage collector is named Orinoco. It divides the heap memory space into 2 regions: young generation and old generation. And the young/old generation take different strategies. The minor GC for the young generation applies a much faster but space consuming algorithm called Scavenge.
The . NET garbage collector can absolutely handle circular references.
To handle the problem of circular references in C#, you should use garbage collection. It detects and collects circular references. The garbage collector begins with local and static and it marks each object that can be reached through their children. Through this, you can handle the issues with circular references.
To be completely honest we would need a quick look at some test code where you replicated this but I have a general idea of what you are experiencing. If I am wrong and you can provide some test code that proves this, please let me know.
As you seem to already know, to 'clean up', Javascript wants no more references to the item looking to be freed.
A simple example:
// Currently not eligible for garbage
var myObj = {
data : 'test'
};
// Reference data inside myObj
// A unique identifier to myObj.data now exists
var myData = myObj.data;
// Whoops
myObj = 'something else';
// Because myData exists, so does data and can not be freed either, understandable
// This sounds simple and logical but most do not understand what is happening in the engine
// A relationship has been born between 'myData' and 'data' and as long as it exists, it is not eligible for garbage and remains in memory
console.log( myData );
Your code is probably more complicated than this but this might help explain how, somewhere, the garbage can not be collected as the scope chain can be followed to a reference.
Consider the following
function oops(text){
function doStuff(){
return text.toLowerCase();
}
return doStuff();
}
// 'doStuff' stays alive thanks to 'test' below.
var test = oops('closure');
the function doStuff
will not be garbage collected because it is being referenced by test
.
// You can see where this is headed. We have 2 references to the same 'doStuff' function object with separate unique identifiers now below.
var test2 = oops('closures...');
// This is now another unique identifier to 'doStuff'
var test3 = test2;
// doStuff survives yet still
test = 0;
test2 = 0;
// Now we let the function object of 'doStuff' be freed because there is no longer any references to it
test3 = 0;
This is essentially a memory leak we created. Each time you call oops
you are creating a function object doStuff
with a unique identifier.
A way to avoid this could be
function doStuff( text ){
return text.toLowerCase();
}
function oops( text ){
return doStuff();
}
var test = oops( 'closure' );
Now we have no memory leaks. doStuff
is being invoked and not created.
A closer look at your code and you will find you are probably doing this somewhere.
If you are messing with elements and I think you might be, IBM has a good article about circular references you may want to take a look at.
It's late and some of this was untested, but the theory is still there so if I misspelled something etc, let me know and I can take a look tomorrow for future visitors to this page.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With