I'm calling a function 50 times a second, which does some expensive things as it is painting alot on a <canvas> element.
It works great, no problems there, but I just took a look at the memory usage and it was stealing 1MB a second of my RAM. Chrome seems to garbage collect, as it went down each minute or so, but then the usage grew again.
What I tried is putting return at certain places in my function so as to decide what part of my function exactly causes the leak. I've been able to cut it down to a specific line of code, after which the evil part comes, but I don't really know how to solve it.
My questions are:
What tool is available to effectively measure JavaScript memory leaks in Chrome?
Would it be effective to set variables to null / undefined after they have been used, something like disposing them?
If the source code is really necessary I wouldn't hestitate to post it here, but I must admit that it's both long and perhaps a little ununderstandable for others.
I'm just going to pull this quote directly, linked from the article;
Speaking of memory leaks, breaking circular references — the cause of the leaks — is usually done with simple null assignment. There’s usually no need to use delete. Moreover, null‘ing allows to “dereference” variables — what delete would normally not be able to do.
var el = document.getElementById('foo');
// circular reference is formed
el.onclick = function() { /* ... */ };
// circular reference is broken
el = null;
// can't `delete el` in this case, as `el` has DontDelete
For these reasons, it’s best to stick with null‘ing when breaking circular references.
delete Explained
Look at heap profile under the Profiles tab in Chrome's developer tools for information about memory usage.
You can do the following to prevent memory leaks:
Test your code with JSLint, to see if that will give you some pointers.
Use the var keyword to give your variables function scope, so they can be garbage collected when they go out of scope. Without the var keyword variables have global scope.
Use delete variable; statements to remove the object as well as the reference from memory. Setting the variable to null will only remove the object from memory, but not its reference.
Related
Do we need to unset variables in JavaScript, and why?
For example in PHP it's recommended to unset all temporary variables in all kind of loops to keep memory free and avoid variables duplicates.
But anyways according to php - what's the benefit of unsetting variables? question:
Is it true that unsetting variables doesn't actually decrease the memory consumption during runtime?
-Yep.
So should we delete window.some_var;?
Or we should use some_var = null?
Or we should not unset variables to avoid additional CPU cycles?
UPD:
Related questions:
How to unset a Javascript variable?
How to remove a property from a javascript object
No, plus in some cases you can't delete variables in the global scope. Variables that are properly declared using the var keyword cannot be deleted (implied global variables can be deleted, on the other hand. Always use the var keyword to declare variables).
Also, javascript engines have this thing called garbage collector that automatically looks for variables that are no longer used or referenced somewhere when your code is 'running'. Once it finds one, it'll shove it off immediately into the Abyss (deletes the variable in the memory)
No, it is not necessary to delete variables when you’re done with them. If you have so many enormous, global variables that this is actually a problem, you need to rethink your design.
And yes, it’s also silly in PHP, and no, it has nothing to do with avoiding “additional CPU cycles”.
Specifically:
“Unsetting temporary variables in loops”
They’re temporary, and probably either a) integers or b) references that take up about as much space as an integer. Don’t bother.
“Avoiding duplicate variables”
Again – references. Setting things that are still referenced elsewhere to null is pointless.
If you feel like it’s clutter, that is a good sign that more things should be going out of scope (i.e. use more functions).
In most other cases that you haven’t mentioned, the engine is also smart enough to manage your stuff properly. Do not optimize prematurely.
David Flanagan answers this quite nicely in his book, JavaScript: The Definitive Guide:
The JavaScript interpreter performs automatic garbage collection for memory management. This means that a program can create objects as needed, and the programmer never needs to worry about destruction or deallocation of those objects. When an object is no longer reachable – when a program no longer has any way to refer to it – the interpreter knows it can never be used again and automatically reclaims the memory it was occupying.
This doesn't mean that memory leaks can't happen in JavaScript. Far from it. Circular (or cyclic) references are a frequent problem in browsers which implement reference counting, as documented here by IBM:
A circular reference is formed when two objects reference each other, giving each object a reference count of 1. In a purely garbage collected system, a circular reference is not a problem: If neither of the objects involved is referenced by any other object, then both are garbage collected. In a reference counting system, however, neither of the objects can be destroyed, because the reference count never reaches zero. In a hybrid system, where both garbage collection and reference counting are being used, leaks occur because the system fails to identify a circular reference. In this case, neither the DOM object nor the JavaScript object is destroyed. Listing 1 shows a circular reference between a JavaScript object and a DOM object.
If you're worried that your website contains a JavaScript memory leak, Google has a tool, aptly named "Leak Finder for JavaScript", which can help you find the cause.
Further reading: What is JavaScript garbage collection?
I've rolled my own javascript server side language called bondi. Just recently upgraded to the new spider monkey.
Now that JS enter local roots and leave local roots function is gone/useless from the 1.8.5 api, is it enough to just use anchor pointer(JS_AnchorPtr(varname)) at the end of your function calls to make sure the compiler isn't removing references to keep the garbage collector happy?
I've been testing it by removing all my references to JS_EnterLocalRootScope (see here)
/ Leave local root scope and adding JS_AnchorPtr() to the bottom of the script.
I looked up AnchorPoint function in the source code of spider monkey. Guess what... it does nothing. There's no doco for it either. I'm using it just so that I can get a mention in of those variables so the garbage collector doesn't kill them.
Well, blame seems to say that bug 519949 is recommending you use js::Anchor so that the conservative stack scanner will pick it up.
Note that the conservative scanner can find any GC thing that's on the stack or in registers, so the only really tricky case is where you use derived values when the "owning" GC thing may be dead, like so:
{
JSString *str = GetMeSomeStringYo();
const jschar *chars = str->chars();
// Note, |str| is not "live" here, but the derived |chars| is!
// The conservative stack scanner won't see |chars| and know
// to keep |str| alive, so we should be anchoring |str|.
DoSomethingThatCanCauseGC();
return chars[0];
}
If you're using C the JS_AnchorPtr at the end of the functions should be enough. You are correct that the function has a nop implementation! The idea is that, so long as it's performing a call to a shared object symbol with the variable to keep alive as a parameter, the calling function will have to keep that value around in machine state in order to perform the do-nothing call. This is more sucky for perf than js::Anchor.
There's one potential trap in the unlikely case that you're statically linking against SpiderMonkey and have Link Time Optimization enabled: the cross-object call may be inlined with a null implementation, eliminating liveness of the variable, in which case the same GC hazards may pop back up.
var Obj = function(){}; var X = new Obj();
will X = null properly clear memory?
Also would this be equivalent?
var Obj = function(){};
var X = {};
X.obj = new Obj();
delete(X.obj);
EDIT
It would seem that although deleting X.obj would NOT immediately clear memory, it would help the garbage collection. If I don't delete X.obj, there would still be a pointer to an object and so the GC may not clean it up.
Although I'm picking #delnan's answer, if you're reading this you should def also catch Benubird's article.
I also notice I accidentally wrote delete(X) originally instead of delete(X.obj) - sorry.
The short answer is that you don't. delete simply removes a reference (and not in the way you try to use it, see the above link - delete is one of those language features few people actually understand), nothing more. The implementation clears memory for you, but it's not your business when (and even if, strictly speaking - this is why one shouldn't rely on finalizers in GC'd languages that offer them) it does. Note though:
Only objects that can be proven to be unreachable (i.e. no way to access it) to all code can be removed. What keeps references to whom is usually fairly obvious, as least conceptually. You just need to watch out when dealing with lots of closures, as they may capture more variables than you think. Also note that circular references are cleaned up properly.
There's a bug in old (but sadly still used) IE versions involving garbage collection of JS event handlers and DOM elements. Google (perhaps even SO) should have better material on my memory.
On the plus side, that means you won't get dangling pointer bugs or (save of course the aforementioned pitfalls) memory leaks.
No, that will not clear memory.
Read this:
http://perfectionkills.com/understanding-delete/
No - Javascript runs GC when it feels like it.
The Delete method only deletes the reference - not the object. Any other references would be left out in the open waiting for the garbage collector.
JavaScript has its own GC, and it will run around and clean things up when nothing refers to them anymore.
I still think it's a good practice to null objects.
Deleteing an object also helps the GC because it will see something dangling, and say "I'm going to eat you because you're all alone (and now some cynical laugh)".
You should look at Deleting Objects in JavaScript
Even though there's a GC, you still want to ensure your script is optimized for performance as peoples computers, browsers, and fricken toolbars (and the number of them), will vary.
Generally speaking, memory management in Javascript is user-agent-specific. The basics of the garbage collector are through reference-counting. So, by setting a reference to null (using the delete keyword or by explicit assignment), you can assure yourself that a reference will be cleaned up, IF the object does not have any references that will live outside of its creation scope. That being the case, the GC will have already cleaned up any objects or variables whose scope has ended without your explicitly setting it to null.
There are some things to take care of, though - circular references are easy to create in JS, especially between a DOM element and an object. Care must be taken to clear (or not create in the first place) references to and/or from DOM elements within objects. If you do create a to/from reference related to DOM, be sure to explicitly clean them up by setting the references to null - both on your object and on the DOM element. Simply setting a parent object to null is not sufficient if there are child objects with references to/from DOM or localStorage because those references will live on, and if there was any reference from the child to the parent, then the parent will live on in memory because of that reference.
Web pages can actually leak trash in your memory this way - after you navigate away, the circular references keep objects and DOM elements in memory until you've restarted the browser!
An article on the subject: http://docstore.mik.ua/orelly/webprog/jscript/ch11_03.htm, and another detailed look: http://blogs.msdn.com/b/ericlippert/archive/2003/09/17/53038.aspx
JavaScript memory is generally handled similarly to Java - I mean there is (or there should be) a garbage collector which would delete the object if there is no references to it. So yes, simply "nullifying " the reference is the only way you should "handle" freeing memory, and the real freeing is the JS host part.
I am given with a project that my seniors worked on, this project is developed keeping in mind that the whole page should never be reloaded. So obviously everything went into ajax. And it has 100's of lines that go something like this.
function iCreateProblems()
{
//some rubbish
document.getElementById('some_rubbish').innerHTML=obj1.responseText;
}
and a typical response text is "<div onClick="handleMe()">some thing stupid</div>";
There are three main div's on the page and everything is repeatedly loaded and reloaded into these div's. Now as far as i understand, this will clearly give away to memory leak, right? So how do i fix this? There are about 8000 lines of code that go in this manner. Is there a way i can fix the memory leak? There are hundreds of handlers that are assigned like this. What do i do now?
No, it shouldn't. You do not handle memory directly in js; garbage collectors remove everthing unneeded and you don't need to explicitly delete on divs' contents if you overwrite the content.
Without seeing the rest of the code there's no way to tell. Despite what people are saying here, it's very easy to create a memory leak in JS and not notice it. The way JS garbage collectors usually work is by marking variables that are "reachable". Variables become considered "unreachable" when their "mark" is taken off and not reapplied, (which is to say, they're completely unreachable by any of the programmer's functions or scopes). After the mark is removed, they're eventually cleaned up by the garbage collector.
One contrived example of a memory leak would be:
(function() {
var xhr = $.get('http://google.com/');
$('a').click(function() {
console.log('hello');
});
})();
As long as that element exists on the page, with that event listener bound to it, the variable xhr will never be cleaned up by the garbage collector. Even though xhr is never used anywhere in your code, the garbage collector will refuse to clean it up because it is still "reachable" by your event listener.
edit: I should also mention, there is also the possibility of a memory leak occurring from bugs in a poorly written JS engine. (See also: Internet Explorer). Most DOM libraries account for this and make sure to avoid these problems, but it can still happen. For these memory leaks you need to find a workaround for that particular engine.
I'm concerned that I might be using a code pattern that leaks memory. Here's a pseudocode example:
window.user = new User();
user.getBasicInfo(function(basicInfo){
user.name = basicInfo.name;
user.getDetailedInfo(function(detailedInfo){
user.favoriteColor = detailedInfo.favoriteColor;
});
});
In other words, I'm not using the 'this' keyword to refer to the user object; I'm referring directly to the user object stored within the window object.
Obviously, the JavaScript 'this' keyword has given lots of people lots of trouble. I've seen some people rename 'this' to make it more clear as they descend a scope chain:
window.user = new User();
user.getBasicInfo(function(basicInfo){
var userInOuterScope = this;
userInOuterScope.name = basicInfo.name;
userInOuterScope.getDetailedInfo(function(detailedInfo){
var userInInnerScope = this;
userInInnerScope.favoriteColor = detailedInfo.favoriteColor;
});
});
Not as pretty, but it seems like the scope chain might be less convoluted in that case.
Can the first approach leak memory? Can the second? To avoid leaking memory, must I pass everything as a parameter (and never refer to objects outside of the current scope)?
The potential to "leak memory" is not something relevant to the question you seem to be asking. That is, neither of the approaches have implications on memory use, at least not in any way clear to me.
The reason you might prefer to make use of the this facility in your code is that you might want a population of objects. In your case, you're apparently using the object as a singleton, so it makes no difference. However, that's really a special case, and you'd quickly find that it doesn't work so well if you've got 100 "User" objects.
Preserving the value of this (and it's not really "renaming" this; it's copying its value into another variable) inside a closure could result in a memory leak, or rather, could be part of a larger memory-leaking setup, but it's not problematic in and of itself. Making copies of object references is something that happens all the time.
edit — the "leakage" problem with closures comes about when a combination of things happens:
Some objects are referenced by variables in the closure scope (not weird or harmful in and of itself);
Functions with references to the closure scope "escape" from a function call, either by being returned or by being exported via global state side-effects (like registering an event handler) (also not weird or harmful in and of itself);
The population of these exported functions grow, or the functions themselves allocate more room when they're invoked and preserve references to the space allocated in the closure, or the exported functions end up directly referenced by DOM nodes (this is particularly a problem in IE).
Really, JavaScript doesn't have any unique problems with memory leaks that any language with real closures has. For a vast amount of actual JavaScript software in this world (utility code wired into web pages), it's pretty rare that memory leakage is a problem, I suspect, though the IE issue with DOM references has probably crashed a few browsers over the years (which probably hardly surprised the hapless users).
I don't like pushing frameworks on people, but it's definitely true that framework authors must worry about this stuff. Trusting in your framework to keep the DOM clean by making sure you only attach event handlers and data to the DOM via framework facilities is therefore a Good Idea.
It doesn't appear that you have any circular references in your code, so I wouldn't worry about memory leaks. You're not setting objects equal to other objects as far as I see ( http://jsfiddle.net/Akkuma/UTL3B/ as a quick example how it could lead to memory leaks).
Here are a few references on memory leaks
http://www.ibm.com/developerworks/web/library/wa-memleak/
http://www.javascriptkit.com/javatutors/closuresleak/index.shtml
http://javascript.crockford.com/memory/leak.html
Additionally, you can use Chrome's Heap Snapshot tool to be able to tell whether or not you are having memory leaks worth worrying about.
JavaScript's this is not the same this like Java's or C#'s. It represents the current context of something being executed.