If I have an object that contains 2 sub-objects, and I delete the pointers to the parent object and one of the child objects, but I still have a pointer to the other child object, will JavaScript delete the one child and the parent, or will the whole parent object remain even though it's no longer addressable?
I know I could use delete to remove the other child element, but that still leaves the parent. And I want to understand GC better and whether this explicit cleanup is necessary.
var parentObj = {
A: { subObjA: 'data' },
B: { subObjB: 'data' }
};
var persist = parentObj.B;
parentObj = null;
After this, will the parent object and subObjA be deleted since they are no longer accessible. or will the whole object remain because I have a pointer to subObjB?
The parent and sibling will be garbage collected (in modern Node and V8 implementations). Because the object at parentObj.A
has no reference to parentObj
itself, the Mark-and-Sweep algorithm determines (correctly) that it is no longer worth keeping around.
You can test this using WeakRefs
or FinalizationRegistry
and forcing garbage collection with Node's gc()
function or Chrome's devtools. WeakRefs
allow you to maintain access to an object without affecting the garbage collector's behavior, and FinalizationRegistry
will call a provided callback when an object is collected.
const registry = new FinalizationRegistry(label => console.log(label, "has been collected"));
var parentObj = {
A: { subObjA: 'data' },
B: { subObjB: 'data' }
};
var childA = parentObj.A
registry.register(parentObj, 'parent');
registry.register(parentObj.A, 'childA');
registry.register(parentObj.B, 'childB');
parentObj = null;
Output
childB has been collected
parent has been collected
Or, if you prefer weak references
var parentObj = {
A: { subObjA: 'data' },
B: { subObjB: 'data' }
};
var weakParent = new WeakRef(parentObj)
var weakChildA = new WeakRef(parentObj.A)
var weakChildB = new WeakRef(parentObj.B)
var strongChildA = parentObj.A
parentObj = null
// <Collect Garbage>
weakParent.deref() // undefined
weakChildB.deref() // undefined
weakChildA.deref() // {"subObjA": "data"}