First, I read and researched extensively on this issue. There is already a ticket with jquery UI which I'm following. And I know a way around this bug but I'm very curious as to why this occurs. I believe the bug is due to a closure but my javascript-fu isn't expert.
I figure that the jquery UI team has better things to do than spend energy on an IE6 bug. So I wanted to bring this out to the general javascript public.
The following is a test case:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jquery ui memory leak test</title>
<script type="text/javascript" src="jquery-1.5.js"></script>
<script type="text/javascript" src="jquery.ui.widget.js"></script>
<script type="text/javascript">
(function($) {
$.widget("ui.test", {
_create: function() {
}
});
$(document).ready(function() {
for (var i = 0; i < 1; i++) {
$("#container").append("<div id='inner'></div>");
$("#inner").test();
$("#inner").test("destroy");
$("#container").empty();
};
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>
I've tested using all combinations of jquery 1.4.4 and 1.5 and jquery-ui-1.8.9 and jquery-ui master (as of writing) but they all produce the same result.
My test widget is I believe the simplest you can get.
If you test using sIEve, you can spot the leak. Otherwise, increase the counter to something like 1000, and you will see the memory increase pretty easily. There is another tool from Microsoft you can use to detect leak as well.
So the leak is due to the custom event binding in the widget's _createWidget
method:
var self = this;
this.element.bind( "remove." + this.widgetName, function() {
self.destroy();
});
So, if I comment those out, there is no leak. I am using 1.8.9 rather than master since 1.8.9's widget code seems simpler (master has changed a bit).
Now, if I bind the same event outside of the widget altogether, there is also no leak. For example, I'd insert the following code after I create the widget but before destroy:
$("#inner").bind("remove.test", function() {});
I purposefully added a no-op function but it doesn't matter what's inside the callback function. You could argue, since I am doing destroy manually afterward, the binding isn't necessary. But that isn't the point.
So my question is why does the original code, the binding call from within the widget code leak? My suspicion is that it's due to a closure but I can't explain it.
Can someone explain this?