ugrás a tartalomhoz

Douglas Crockford az Internet Explorer memóriaszivárgásokról

Edit · 2006. Okt. 20. (P), 13.47
Ehhez a blogmarkhoz kapcsolódva legépeltem az IE memóriaszivárgás kezelésére vonatkozó részt az előadásból - most tanulom az AJAX-ot és nagyon hasznosnak találtam. A harmadik előadás elején van, utána is van még néhány jó tippet AJAX témában.

There is a problem of event handlers and garbage collection, particularly in IE. Ordinarily we shouldn't have to worry about memory leaks, because Javascript is an automatically managed memory system, which is good, and the browser is too. So we cannot explicitly allocate memory from the browser and de-allocate it - that's all done automatically for us, which is good. Sometimes in a memory-managed system like that it is possible to accidentally hang on to too much state, you might have a variable that contains a reference to a really big structure that you're not using any more, in those cases it's probably a good idea to [...] garbage collector can get out that stuff. Generally it's not a problem, not something that [we have to] worry about, except when there are real errors in the implementation of these things that you do have to worry about it.

The biggest memory leak that we do have to be concerned about is in IE6. So because of that you need to explicitly remove all of your event handlers from your nodes before you remove them from the DOM.
Memory Leaks on IE6
  • Explicitly remove all of your event handlers from nodes before you discard them.
  • The IE6 DOM uses a reference counting garbage collector.
  • Reference counting is not able to reclaim cyclical structures.
  • You must break the cycles yourself.
The reason for this is that IE6 uses a memory management technique called reference counting. Reference counting has the advantage that it's really easy to implement. Every time you create a pointer to an object, you [..] its reference count by 1, and every time you cause a pointer to not point at it any more, you decrement it by one, and when it goes [down] to zero it's garbage and you get rid of them. The problem with that technique is that it doesn't work with cycles. When you have 2 objects that are linked to each other, but nothing else is linked to them, technically they are garbage, but they each have a ref count that's one because they are pointing at each other. So they never get reclaimed and they'll always consume memory. And if you get enough of those in memory, eventually you get starvation.

Microsoft didn't think that was a problem, because you don't have cyles in a DOM structre - it's a tree, it's strictly acyclical, so that makes reference counting safe. The thing that they didn't consider was that when you add an event handler to a DOM node, you have a pointer going back to Javascript's space. And in Javascript's space you might also have, say, a variable pointing back to the DOM node. In fact that's pretty likely, because you have to have a reference to the DOM node in order to attach the event handler to it. The way the closures work, generally they will stay bound together. Microsoft has tried to convince the programming community that it's your fault, that you shouldn't be using closures when writing in Javascript, but in that language you cannot avoid using closures. Any time you are using an inner function you are using closures. So avoiding closures is not good advice. So what you have to do is fix it where the problem actually exists. Which is on the DOM side. And you have to do that by explicitly removing the event handlers from the DOM nodes before the DOM nodes get detached. So you have to break those cycles. This wasn't an issue for a long time because applications were page-oriented, you'd show a page, be on the screen for a minute or two, then you go onto another page, and during the time you were on the screen there wasn't all that much script running. So for years nobody noticed that this [...] was going on, because of the usage pattern. But when you're doing Ajax applications, where that page could be on the screen for hours, and you've got intense Javascript running the whole time, it quickly fills up and you get memory starvation and destruction.
Memory Leaks on IE6
  • That was not an issue for page-view driven applications
  • It is a showstopper for Ajax applications
  • It will be fixed in IE7
This will get fixed in IE7, but IE7 is still a way off, and even though they will be pushing it automatically I expect it's still gonna be years before everybody gets it. At least before a critical mass occurs. In the meantime we have to deal with [IE6]. So what we have to do is remove all event handlers from all deleted DOM nodes, it must be done on all nodes before we use removeChildren or replaceChild, anything that pulls it out, also on inner HTML [...] before it does the replacement. So if we do any of these, we have to remove the event handlers.
Memory Leaks on IE6
  • Remove all event handlers from deleted DOM nodes
  • It must be done on nodes before removeChild or replaceChild
  • It must be done on nodes before they are replaced by changing innerHTML
Here's a way to do that:
Breaking links in the DOM

function purgeEventHandlers(node) {
	walkTheDOM(node, function(e) {
		for (var n in e) {
			if (typeof e[n] === 'function') {
				e[n] = null;
			}
		}
	});
}
Or you can use YUI's purgeElement method.

Using our old friend walkTheDOM, we pass it this function. And what this function does, it will look at all the attributes, and if it finds any that look like functions, null them out. And if we call this on an object that we are gonna delete, this will take care of it.

As an alternative, you can use YUI, it has a purgeElement method that will do this for you.