Wednesday, December 9th, 2009
First off, for those who want a quick summary, the slides from the Javascript memory leaks seminar are available.
Main points:
- What a memory leak is
- How memory leaks occur in Javascript
- How to avoid memory leaks
- Effects of memory leaks
- How much browsers are affected by leaks
- Security ramifications of leaks
- Detection of leaks
- What is a memory leak?
Basically, a memory leak is when a program does not release memory it requested. Usually this is occurs because the programmer forgot to tell the program to “let go of” (free) the memory because it was no longer needed. A (loose) analogy to this could be like renting a movie and not returning it (because you forgot to) until you get a call from the rental company that you have to return the movie. While you have that copy, nobody else can rent it, and since you’ve already watched it and aren’t using it anymore, it should be returned.
In compiled languages like C this is not a hard mistake to make, as memory management often has to be handled by the programmer. However, in Javascript, memory management is mostly taken care of for you. You just have to watch out for memory that cannot be automatically cleaned up for you (like the global scope).
How can memory leak in Javascript?
- In Javascript, misuse or accidental use of global scope (e.g. some anonymous functions, undeclared variables) can cause a memory leak. The anonymous functions are mentioned below.
- As for undeclared variables, something you may not know about Javascript is that if you do not explicitly declare a variable in a function (e.g. var foo), it will go into the global scope instead of the function scope. This can drastically mess up your memory usage but can also cause unpredictable issues with your code, too.
- Closures with DOM elements / event handlers: Although this is mostly an issue with Internet Explorer’s way of handling these, closures that work with DOM elements or event handlers will tend to hang around in memory and since you have no pointer to these closures, you can never free that memory.
- Event handlers: Again, this is mostly a problem with IE’s way of handling DOM elements. While the Javascript engine is intelligent and can recognize what object points to what (as is being pointed to), the HTML engine only keeps a count of references. You may already see the problem here: the Javascript event handler is ready to be freed from memory, but it is unable to because it knows the HTML engine’s element is pointing to it, while the element is not ready to be freed because it knows it has a reference to something – but not what. Because of this, even once the web page is gone, that pair of objects remains in memory. This is quite plainly a leak, and is quite annoying because it affects all web pages which use these, not just web applications (since most other leaks can be solved just by browsing to another page, but web applications tend to be held open for long periods of time).
- The best way to deal with this situation is twofold:
- To have a an object which keeps track of where handlers have been attached and unattach the handlers once the elements are no longer in the HTML.
- To have a handler onunload() to go through the elements where handlers have been attached and unattach them.
- Or, as an alternative to the aforementioned two, only use a global handler on the document body and delegate to listeners yourself. That way you only have one listener to unattach onunload(); but it may be more or lesswork.
- Circular references: As Javascript engines improve, this is becoming less and less of a problem. In fact, the only browsers who were not able to deal with these are IE6 and IE7. IE8 seems to deal with it to some degree, so only a quick review is necessary.
- A circular reference is when one object refers to another and the latter object refers to the first in one way or another. An example of this is how trees tend to do this. You’ll usually have a reference to the previous node and the next node in the same object, and it’s adjacent nodes will do the same. Because neither object is ready to be freed (they know they’re still being linked to), they do not let go of their links to the other object(s), and thus stay in memory.
How to fix memory usage
- Use the global scope only when appropriate. Anonymous functions are okay but they can stick around in some situations and then you have no way to free them even if you wanted to.
- Always declare variables in functions when or before you use them. Ideally, this would be done at the start of the function, but you can do it inline too (e.g.
for (var i = 0; i < somelogic(); i++)). - Use a collector to keep references to elements with event handlers and avoid closures with event handlers (and functions that attach event handlers) OR use a global event handler that delegates to listeners.
- Avoid dealing with DOM elements in closures OR remember to null them afterward.
- Detach circular references when you are done with them. (Try to avoid them altogether, really.)
But are leaks really an issue? What do they do?
- Leaks will slow down the browser as the it consumes more and more memory.
- Leaks will slow down the operating system and other processes as the bigger process is given more room.
- Some browsers handle leaks better than others but that does not mean you can be lazy. IE8 uses whole separate processes per tab (at least in Vista) therefore all of the memory is reclaimed when a tab is closed. Similarly, Chrome uses a virtual separate process (or a thread) per tab, so all the memory is (presumably) reclaimed when a tab is closed). Usually the “extra load” will continue until closed, so this information does not only apply to web applications!
How bad is the leak situation?
The leak situation has improved quite a bit recently, but until Internet Explorer improves its Javascript engine, this cannot be avoided. The Javascript memory leaks seminar slides have graphs of results of a few tests.
How can I know if my web page/application leaks?
You can use the Internet Explorer JavaScript Memory Leak Detector (v2), Mozilla’s Performance Tools, or some paid solutions like the JavaScript Memory Validator.
References / More information
- IBM’s Memory leak patterns in JavaScript article
- Microsoft’s Understanding and Solving Internet Explorer Leak Patterns MSDN article
- Too many forum and mailing list discussion threads to mention.
SilenceIT Inc.
(613) 627-4370
(613) 288-0555
You can skip to the end and leave a response. Pinging is currently not allowed.