How to fully remove temporary elements? - javascript

I am dynamically adding a 'div' node inside a function that will only be needed temporarily. I have already used < parent >.removeChild to detach it and then set it to null, but I am curious to know what happens to unattached nodes created in a function when it goes out of scope?
If the nodes remain in memory but unattached:
A) Is setting to null even necessary or does it automatically go away on return?
and if so is setting to null the proper way?
B) Does anything need to be done with its properties? (such as node.style.position)
C) If it contained additional children, would they need to be handled individually or would they go away when their unattached parent node is set to null?
D) What tool(s) can be used to view these kinds of unattached resources?
Here is an example function for discussion purposes:
function dpi(){
var res={},
div=document.createElement("div"),
body=document.getElementsByTagName('body')[0];
div.style.position="absolute";
div.style.width="1in";
div.style.height="1in";
div.style.left="-100%";
div.style.top="-100%";
body.appendChild(div);
res["xdpi"]=div.offsetWidth;
res["ydpi"]=div.offsetHeight;
body.removeChild(div);
div=null;
return res;
}

JavaScript uses automatic memory management. That is, it uses a garbage collector, where anything that's not referenced will be freed up automatically. To answer your specific questions:
No, it is not necessary to explicitly set it to null — it'll go away when you return.
No; those should be taken care of automatically.
No; children should also be taken care of automatically.
Perhaps some sort of garbage collector debugger.
I should note that some older browsers have reference-counting implementations of garbage collectors, where if you have cycles (an element pointing to something else pointing back to the element, which often occurs in event listeners), they may not be collected and you'd have to break the reference explicitly, but most browsers today are smarter.

The garbage collector, when it runs, will seek out anything that is not connected to anything else (roughly - it has some special stuff to handle circular references that aren't connected to other things). Basically, if there is no more variable pointing to the element, it will be removed from memory at the browser's convenience. Now, that might be instant, or it might be when the browser arbitrarily decides it's using too much memory and decides to clean up a bit. I don't believe there is any specification on how the browser should garbage collect.

Related

Why browser becomes slow with large number o DOM elements

I know this question sounds very trivial, but I just want to know how 'browser processes DOM and what makes it become slow with large number of DOM elements? Is this just about the size? What if DOM elements are not high in number but javascript objects are? Would it still respond slow?
I guess, if there are events attached to javascript objects and we don't dispose them, it responds slow because it has to execute all the event handlers (in a sequential manner), but other than that what are the other reason where 'memory leak' slows down the browser? (Assuming browser has consumed lots of memory but enough memory is still usable in system).
Update:
Surprisingly, CPU and memory usage is always under control while browser responds slow.
If a page is loaded with all its elements and it doesn't change, then there is no reason why it should be slow no matter the amount of DOM elements. However, if you have a dynamic page, there are loads of operations that cause the entire layout to redraw itself. This is called layout thrashing and can have dramatic effects on performance.
The most obvious is that your browser consumps all your memory and when it comes time to render something during scrolling, for example it has no more memory.
If there are no memory issues, then JohanP is write - there is no reasons.
Why do browsers slow down when loading a lot of data? Because they have to load a lot of data. Large images are obviously the worst culprit in terms of load speed, but page load is directly correlated to the number of kilobytes being transmitted. If you have a lot of code, it's going to have a large filesize.
As for JavaScript, there are four main causes of leaks:
Accidental Global Variables -- Variables not explicitly defined will assume a global scope:
function foo(arg) {
bar = "This is a global variable";
}
Forgotten Timers Or Callbacks -- When declaring a variable in a timed function like setInterval(function() {}), the variable still exists at the end of the interval.
Out Of DOM References -- When assigning reference to an element, which later is removed, the reference still exists:
var button: document.getElementById('button');
document.body.removeChild(document.getElementById('button'));
Closures -- Loops often don't get closed 'correctly', losing variable scope, and leaking in the process. See JavaScript closures.
See 4 Types of Memory Leaks in JavaScript and How to Get Rid Of Them for further information on JavaScript memory leaks.
Hope this helps!

How to know if element created with document.createElement still exists

I'm creating an anchor element using document.createElement in my PhantomJS tests like this:
var mockLink = null;
beforeEach(function() {
mockLink = document.createElement('a');
});
it('should foo', function() {
// Use mockLink in some way
});
I want to clean up the element in the afterEach code so that each test will have a newly-created instance of it. Unfortunately, element.remove() isn't supported in PhantomJS. Source
afterEach(function() {
mockLink.remove(); // Error!
});
And I want to do this without adding the webpage plugin.
removeChild is supported by PhantomJS, but my newly-created element doesn't have a parent:
mockLink.parentElement // undefined
mockLink.parentElement.removeChild(mockLink); // doesn't work
mockLink.parentNode // also undefined
My newly-created link also doesn't seem to be on the document at all.
mockLink.href = 'www.google.com';
document.getElementsByTagName('a'); // doesn't contain google.com
So I can't do
document.removeChild(mockLink);
mockLink.ownerDocument.contains(mockLink) also returns false
It seems like there are no references to mockLink stored anywhere besides my mockLink variable, meaning that I can just set mockLink equal to null if I want to let that memory be freed up by garbage collection. But how do I verify this works? If I set any other variable to mockLink and then console.log it, it will still come out as defined since it will be a new reference to the same space in memory. How do I verify that mockLink is really being deleted when I set the variable to null?
You've found yourself a conundrum.
If you kill all references to the element by setting mockLink = null and making sure there are no other references to the element, then the garbage collector should be able to free that object.
But, you cannot verify that because in order to verify that the element is no longer available, you'd have to keep a reference to it, but that would prevent it from getting garbage collected in the first place. Thus, the conundrum.
This is an issue that can't really be measured directly from Javascript itself.
If you want to design a one-time test to make sure the memory is being reclaimed, then you can take a memory snapshot, create a several hundred thousand objects stored in an array, clear the array, wait a short time for GC to run, take another memory snapshot, repeat the same process several more times and verify that memory usage of the process is not steadily increasing or study the memory snapshot to make sure none of those objects appear in the memory footprint.
If your javascript environment supports weak references then you can create a weak reference to the node. Depending on the implementation notification mechanisms such as callbacks or reference queues that tell you when it has been collected may also be available.
Unprivileged javascript contexts in web browsers currently don't offer such an API. Node.js, Nashorn and browser addon environments do.

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;

Identify javascript closures with developer tools

I am currently developing a website that is pure javascript and relies heavily on the jQuery & jQuery UI libraries (this site is not intended for use by a general public, hence progressive enhancement is not a strict requirement for this project). I am encountering a significant memory leak on executing the following code:
oDialogBox = $("<div>...</div>");
/* Add useful things to the dialog box here */
oDialogBox.appendTo("body");
oDialogBox.dialog({
/* Other dialog box settings here */
close: function(event, ui) {
oDialogBox.dialog("destroy");
oDialogBox.remove();
oDialogBox = null;
}
});
At any given time in this dialog box, I am creating, removing and modifying a large number of instances of jQuery UI buttons, multiselects (per the Multiselect widget created by Eric Hynds) and on click event handlers. According to jQuery UI documentation, calling .remove() on oDialogBox should result in all child widgets being unbound and deleted. Yet my detached DOM tree shows a significant number of garbage elements that the GC isn't collecting.
It is highly likely I have missed a large set of closures that need to be finished off safely. How do I do the following:
1) How do I identify which closures are keeping a given detached DOM object alive (either in Firefox or Chrome)?
2) Assuming the complete set of closures is identified, does anything beyond nulling the variable need to be done to assure marking the DOM element for garbage collection?
3) I have also noticed my list of arrays stored by the page is giant and contains references to DOM elements not being gathered by the GC. Is there a documented best practice for cleaning arrays from javascript and allowing all elements to be marked for deletion? (Note: this is a current prime suspect for the source of the memory leak)
I'm afraid that I don't have a great answer for #1. I haven't found any really good tools for this myself, even given how good the development tools have become over the last few years. The best advice I can give is to always keep things in the smallest scope you possibly can. If things don't escape, it's generally easier to simply figure out where the references must be.
As to #2, there can be further concerns. If the object referenced by variable v1 closes over the free variables of some function, removing v1 will not be enough to make them eligible for garbage collection if another variable v2 closes over v1 in some other function. So I guess if you really mean the "complete set of closures", then you should be all set. But this might get hairy. Again, if most object have references only in narrow scopes, these problems are much less severe.
For #3, what sorts of arrays are you discussing? If it's jQuery collections, then perhaps you simply have too many of them around. The only reason I know for them to stay around for a long time is to bind event handlers to them, and that is almost always better handled by event delegation on parent elements. If it's you're own custom arrays, do you really have a good reason to store references to them in arrays that last for any substantial length of time? I've rarely found one.

Can jQuery.data cause a memory leak?

Would the following piece of code create a memory leak.
According to the jQuery documentation use of the data function avoids memory leaks. It would be useful to confirm whether the following is safe.
var MyClass = function(el) {
// Store reference of element in object.
this.element = $(el);
};
// Store reference of object in element.
$('#something').data('obj', new MyClass('#something'));
Obviously the code as it stands would take up extra memory as long as the DOM element is still connected to the DOM. But I'm guessing you're asking whether it would continue using extra memory after the DOM element is no longer in use.
Update: Thanks to Joey's answer (which he has since deleted), I spent some time reading up on memory leaks in javascript, and it appears my assumptions in the paragraph below are incorrect. Because DOM elements don't use pure garbage collection, a circular reference like this would normally prevent both the DOM element and the javascript object from ever being released. However, I believe the remainder of this answer is still correct.
Without a deep knowledge of how javascript engines implement garbage collection, I can't speak authoritatively on the topic. However, my general understanding of garbage collection makes me think that your code would be "safe" in the sense that after the #something element is removed from the DOM, the resulting MyClass object would only have a reference to an object that has no other connections. The graph algorithms of the garbage collector should be able to identify that the DOM element and its MyClass object are "floating in space" and unconnected to everything else.
Furthermore, jQuery goes out of its way to strip data and events that are associated with a given DOM element once it is removed from the DOM. From the documentation:
jQuery ensures that the data is removed when DOM elements are removed via jQuery methods, and when the user leaves the page.
So assuming you use jQuery consistently, you would only have a one-way reference once the object is removed from the DOM anyway, which makes it that much easier possible for the garbage collector to know it can get rid of these objects.
So as long as you don't have something else referencing the MyClass object once the DOM element is removed, you shouldn't have a memory leak.
I suppose it depends on the Javascritp engine.
You have have the question precisely enought to perform a test. I added a long string in the object and ran the potential leak in a large loop.
As a result, I don't think in leaks in IE8 nor in Chrome.
But I could not reproduce these leakeage patterns either.
This can lead to a memory leak.
the theory of jQuery.data method may use A Data inner class to cache data for the dom element.
of course,when you remove the cache data,jQuery will unreference the data.
but the inner cache is a increasing array,when you you it ,it will go upon.
so ,in the end,there will be very big cache array,which will lead memeory leak.
In a long run web app,this may leak memory crash.
The data attribute only stores string values.

Categories

Resources