I was checking the doc in MDN about garbage collection. When I come across the 'Real-life example' section, the term 'explicitly removed' in below statement confused me.
If the property is not explicitly removed or nulled, a reference-counting garbage collector will always have at least one reference intact and will keep the DOM element in memory even if it was removed from the DOM tree
Can document.removeChild fulfill the criteria of removing DOM element explicitly?
Can document.removeChild fulfill the criteria of removing DOM element explicitly?
The question indicates some confusion: there is no criteria to explicitly remove the DOM node. Removing an element from the DOM, either explicitly or implicitly (by removing an ancestral element from it descends), should make it available for memory collection assuming no reference to the removed element is retained in code. The property mentioned at the beginning of the quoted article refers to the div.circularReference property used in the example, whose value was set to div to create a circular reference back from the property to the element.
Explicitly removing "the property" could be achieved by deleting or changing the property's value, for example with
div.circularReference = null; // or
delete div.circularReference;
Removing the circular reference could be done before or after removal of div from the DOM. The good news is where the article says reference-counting garbage collector are no longer used in modern browsers.
Related
A search didn't quite get me the answer I was looking for.
I am curious if setting a variable to a queryselector is a reference, pointer or value.
Example 1:
// lets assume there is only one ".class"
var element = document.queryselector(".class");
element.classList.remove("effect1");
element.classList.add("effect2");
Example 2:
document.queryselector(".class").classList.remove("effect1");
document.queryselector(".class").classList.add("effect2");
Are these exactly the same thing? Or by setting the variable to the selector, are you saving overhead?
My thought is that if the variable is a value, then the query selector won't search the DOM when the variable is used.
Hope that makes sense.
In Javascript objects are always passed by reference so both examples have the same effect since document.querySelector returns a DOM Element (which is an object).
As a short FYI:
Primitive types are always passed by value
Arrays are also passed by reference
Your first example is much more efficient because you only have to search the DOM once and there is absolutely no difference in their effect.
Javascript is always pass by value, but when a variable refers to an object (including arrays), the "value" is a reference to the object.
var element = document.queryselector(".class"); // element is an object
So both examples are exactly the same. Under the hood is just accessing classList property of element object.
Yes, first code snippet is efficient because we are saving a cycle to fetch DOM nodes again. If we are just accessing dom element nodes a few times let say 10-100 (normally in a mid to large project) then the performance won't be impacted much. I mean you can just ignore that. That won't be a drastic effect.
But yes if we are accessing dom nodes a million times then that effect is noticeable.
Let's check for 1 million times, just to access DOM element nodes.
first = performance.now();
new Array(1000000).fill(1).forEach(() => {
div = document.querySelector('div');
})
second = performance.now();
console.log(`${second - first} milliseconds`); //337.2850000159815 milliseconds
// Result can alter from machine to machine
Hope it is clear now.
I did this simple test in Chromium Console:
var e = document.querySelector('#myElement');
e.remove();
//But here, 'e' still references the original node even though its no longer in the DOM.
I don't want this behavior. I would like 'e' to act more like a Weak Reference, whereby it would change to NULL or UNDEFINED or something indicating the node has been destroyed.
I understand that the problem is due to the fact that the node technically still exists even though its not part of the DOM anymore. I speculate it will hang around until the browser deems an appropriate time to garbage collect it.
So instead of simply doing .remove(), is there a way to really destroy/delete the node so that all variables referencing it will become undefined or null or some effect that can be detected later?
Thanks in advance!
Also, I speculate this behavior will vary highly between browsers. So any feedback that mentions Non-Chromium browsers is highly welcome also. :)
If a standalone variable holds a reference to an object, and that variable can still be referenced, the object will not get picked up by the garbage collector's mark-and-sweep algorithm, and the object will continue to exist at least as long as the variable can still be referenced.
Given a reference to an object, you cannot destroy it such that other references to the object break.
JavaScript doesn't provide the sort of manual memory control you're looking for, unfortunately.
You can put the element into a WeakSet, after which removing the element from the DOM will eventually cause the element being removed from the WeakSet if nothing else can possibly reference the element - but that's not really what you're looking for.
There do exist WeakRefs, an extremely new API, which allow variables to be specially declared such that what they reference can be garbage collected despite them still being referenceable:
const ref = (() => {
const e = document.querySelector('#myElement');
const ref = new WeakRef(e);
e.remove();
return ref;
})();
With the above, calling ref.deref() will eventually give you undefined if nothing else can reference the element and it has been garbage collected. (Until it gets garbage collected, .deref() will give you the element.)
Being a C developer, I feel the urgent need to free memory as accurately as possible. But after reading some posts about memory management in JavaScript I still have some questions about that topic. As far as I understand, there is a garbage collector that will automatically free the memory when an object isn't referenced anymore and the GC can find the time. So an object that is held in a local variable is very likely to be freed when the variable goes out of scope.
Let's assume I have some custom elements (tab control, data table, inputs etc.). The classes of those custom elements have member variables where several data for the specific element is stored. Also event listeners can be attached to the elements the custom element consists of.
Let's say I have following html markup:
<my-tabbar>
<my-tab id="myTab">
<my-input></input>
<my-dataTable></my-dataTable>
</my-tab>
</my-tabbar>
Now I want to remove <my-tab>. Is it sufficient to just do
var element = document.getElementById ("myTab");
element.parentNode.removeChild (element);
element = null;
Or do I have to dereference every object of the child elements and remove their event listeners?
Setting an object to null makes it an empty object. Once the object is out of scope, the GC (when it runs) will clear it up. Setting local objects to null won't do you any good.
Example:
function whatever()
{
var something = null;
console.log( typeof( something ) );
}
whatever();
Output:
"object"
For the removal of a child node, please see this:
Does removeChild really delete the element?
Source(s):
https://www.w3schools.com/js/js_datatypes.asp
It is sufficient to remove the element. You don't even have to set the variable to null afterwards – you can trust the JS engine to free the memory when it goes out of scope.
If I have a map containing the ids of DOM elements and I want to de-reference an entry in the map, so the corresponding element can be picked up by garbage collector, what are the steps I should go through to make sure there is no memory leak? Should I delete or = null on the map entry? What do I need to do about the element itself?
(I assume by "map" you mean "object".)
To permanently remove a property and value from an object, use delete. Using null will have the effect of clearing the value, but retaining the property.
Both will allow the value to be garbage collected.
But to what you're trying to accomplish, if the map only has reference to an ID string, it will have no impact on the element itself. You need to drop all references to the element (in DOM and JavaScript) to ensure the element is garbage collected.
If you create a element within a function like:
function makeDomElement()
{
var createdElement = document.createElement('textarea');
}
And you do not append it anywhere in the DOM i.e. via .appendChild functions, does it still remain in memory? So would you have to do
function makeDomElement()
{
var createdElement = document.createElement('textarea');
delete createdElement;
}
I'm just curious :)
It will vary from browser to browser however the javascript delete keyword has nothing to do with the DOM's createElement method. There is no need to use delete.
What will happen is that the reference to the element currently held in the createdElement will get garbage collected. Now in the case of IE that will mean that the element will have its reference count dropped to 0 so it will destroy itself and release its memory. Other browsers do things differently typically the elements in the DOM are themselves garbage collected objects and will be removed during the same (or perhaps a DOM specific) GC cycle.
Had the element been added to the document then in the case of IE there would be another reference added to the element so when the reference in createdElement is removed the element object would still have a non-zero reference count and continue to exist.
In the case of other browsers where the elements themselves are garbage collected the element wouldn't be collected since the collector would see it in the graph of objects connected to the document.
After the function terminates, there's no longer any reference to the object, ie if the garbage collector works properly, it should be collected (there's an IE bug that prevents objects with circular references to be collected if DOM nodes are involved).
Also, your code is broken as local variables can't be deleted: trying to do so will even throw a syntax error in strict mode ES5.