Im working on a game, and ive seen a lot of memory consuption, im using jquery animate, and after the animation is done, i .remove() the element, my question is, after removing an element from the dom tree, the object still exist in memory?
Javascript is a garbage collected language. That means that an object in memory will be released when no code holds any references to it and (for a DOM object) it's not in the DOM. So, when you remove an object from the DOM, as long as no other part of your javascript has a reference to that DOM object, the DOM object will be cleaned up and it's memory returned to the available memory pool when the garbage collector gets a chance to run.
Keep in mind that when memory is freed by the garbage collector, it may not be returned to the system right away or ever. It may stay as memory allocated to the browser, but it will be available for use by other memory requests within the browser. So, freeing memory in your script won't necessarily make the total memory used by the browser go down.
It is only a memory leak if repeatedly carrying out the same operation over and over causes the total memory used by the browser to continually rise. Only then can you be sure that some memory is being permanently consumed by a "leak".
There are a number of nuances about garbage collection, particularly for older versions of IE, but for modern browsers, mostly what you need to keep in mind is that if you hold a reference to an object in your own javascript data structures, it will not be garbage collected. If you don't hold a reference to it and it's not in the DOM, it will be freed and its memory recycled.
If there are no references to the element, garbage collection will clean it up on its next run. You're just fine using .remove, but don't bother worrying about the garbage collection.
Related
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.
The following code is regarded as causing a memory leak because element maintains a reference to function bar and bar maintains a reference to element via closure (if I understand correctly).
Why does this cause a memory leak? Does it only cause a leak when element is a DOM node?
function foo(element, a, b) {
element.onclick = function bar() { /* uses a and b */ };
}
This is called a Javascript closure and is an expected feature of Javascript. This is not a memory leak in any modern browser.
If the DOM element represented by element is removed from the DOM, then the onclick handler will be garbage collected and then the closure itself will be garbage collected.
During the lifetime of element, the variables a and b will be part of the closure. This is an expected language feature as they are part of the closure that this code creates. When and if, element is deleted from the DOM and it is garbage collected, the closure and its references a and b will be eligible for garbage collection too.
There are some old browsers that did not always handle this properly, but that is generally not considered a design consideration any more for modern browsers. Further, it only caused an issue of consequence if you ran code like this over and over (removing DOM elements each time too) such that a large enough amount of memory was consumed by things that weren't being garbage collected when they should have been. This typically only happened in long running single page applications that had a lot of dynamic DOM stuff going on. But, as I said with modern browsers, this is no longer an issue as the browser's garbage collector handles this situation now.
This code only caused a memory leak in certain old versions of Internet Explorer. Internet Explorer 8 made some changes to memory management which mitigated the problem:
https://msdn.microsoft.com/en-us/library/dd361842(v=vs.85).aspx
As all of the affected versions of Internet Explorer are now thoroughly obsolete, this is no longer an issue you need to be concerned with.
To what extent are jQuery / JavaScript functions stored in memory?
Once the browser has parsed the page, does it go into memory? All of it? If functions are repeatedly called, are they always from memory?
If the portion of memory allocated to scripts is filled (thinking Internet Explorer 6 on a horrible PC here), what happens? (Other than a slow browser...)
Is there a way of seeing how much memory is used by a variable or a function as a whole?
As per my knowledge, once JavaScript code has been parsed by the browser, objects remain in the memory unless dereferenced and garbage collected. Garbage collection is dependent on the JavaScript implementation of the browser though.
You can see the memory usage by JavaScript objects easily in Chrome. See here.
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.
I'm suspecting that if i set div.innerHTML="" instead of using while(div.firstChild)div.removeChild(div.firstChild) the memory will be hogged until the page refreshes or the browser closes.
My question is how do we actully go about testing if my hypothesis is true?
Firstly, whether memory is returned to the system or not depends on the Javascript garbage collector (gc) and therefore results will vary from browser to browser.
It's difficult to measure memory usage by looking at the process as there are several layers of memory management in place. To see how this can have an impact, consider that a huge javascript object might have been erased forever, but that memory might still not have yet been released back to the operating system because the web browser might keep hold of it in case you need to create more big objects. Another example is that most gc routines only run periodically, so it's possible that object is still in memory but will be reclaimed later.
However, it's pretty easy to determine if a particular operation is leaking memory as all you have to do is repeat it in an endless loop. e.g.
remove references to existing html elements
construct new html elements
add them to the page
Try this code:
var div = document.getElementById("test")
while(true) {
// remove operation, change me
while(div.firstChild) {
div.removeChild(div.firstChild);
}
// create some new content
for(var i=0; i<1000; i++) {
var p = document.createElement('p');
p.appendChild(document.createTextNode('text'));
div.appendChild(p);
}
}
My results in Chrome, using the Task Manager (shift+esc):
Leaving the loop running endlessly without deleting anything eventually results in the "Aw! Snap" screen, which indicates memory has been exhausted
Using the removeChild technique leads to memory usage stabilizing at around 750MB
Using the innerHTML technique leads to memory usage stabilizing at around 750MB
If memory isn't leaking you'll notice a pattern similar to this: Increases to 300, drops to 150, increases to 400, drops to 250, eventually stabilising. This is the memory management system running out of memory, triggering the gc to reclaim memory that has been deallocated and increasing the available memory footprint each time until reaching a soft limit that has been set to avoid the process impacting others. This is a typical memory management scheme and more can be found by reading this wikipedia article: http://en.wikipedia.org/wiki/Garbage_collection_(computer_science)
Since both results stabilize, I'd conclude that (for Chrome at least) both techniques work the same though you might get different results from other browsers.
As there doesn't seem to be a difference, removeChild should be preferred as innerHTML is not included in the W3C standard and is frowned upon by some developers. See more here: Alternative for innerHTML?
The reason innerHTML and removeChild have no differences is because underneath, they both have to de-reference elements to stop them from being visible on the screen. Memory leaks are most likely to occur when you have circular references (A points to B, B points to A, nobody else points to either) but this is only a problem in older browsers. This link has some good guidelines about how to avoid js memory leaks: Javascript memory management pitfalls?