Alex Rivera | Logout

jQuery memory leak with DOM removal

Asked 2009-09-22T21:15:00.783
46

Here's a dead-simple webpage that leaks memory in IE8 using jQuery (I detect memory leaks by watching the memory usage of my iexplore.exe process grow over time in the Windows Task Manager):

<html>
<head>
    <title>Test Page</title>
    <script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<script type="text/javascript">
    function resetContent() {
        $("#content div").remove();
        for(var i=0; i<10000; i++) {
            $("#content").append("<div>Hello World!</div>");
        }
        setTimeout(resetTable, 2000);
    }
    $(resetContent);
</script>
<div id="content"></div>
</body>
</html>

Apparently even when calling the jQuery.remove() function I still experience some memory leakage. I can write my own remove function that experiences no memory leak as follows:

$.fn.removeWithoutLeaking = function() {
    this.each(function(i,e){
        if( e.parentNode )
            e.parentNode.removeChild(e);
    });
};

This works just fine and doesn't leak any memory. So why does jQuery leak memory? I created another remove function based on jQuery.remove() and this does indeed cause a leak:

$.fn.removeWithLeakage = function() {
    this.each(function(i,e) {
        $("*", e).add([e]).each(function(){
            $.event.remove(this);
            $.removeData(this);
        });
        if (e.parentNode)
            e.parentNode.removeChild(e);
    });
};

Interestingly, the memory leak seems to be caused by the each call which jQuery includes to prevent memory leaks from events and data associated with the DOM elements being deleted. When I call the removeWithoutLeaking function then my memory stays constant over time, but when I call removeWithLeakage instead then it just keeps growing.

Edit
Report

1 Answer

4

Element removal is an inherent DOM problem. Which is going to stay with us. Ditto.

jQuery.fn.flush = function()
/// <summary>
/// $().flush() re-makes the current element stack inside $() 
/// thus flushing-out the non-referenced elements
/// left inside after numerous remove's, append's etc ...
/// </summary>
{ return jQuery(this.context).find(this.selector); }

Instead of hacking jQ, I use this extension. Especially in the pages with lot of removes() and clones() :

$exact = $("whatever").append("complex html").remove().flush().clone();

And also the next one does help :

// remove all event bindings , 
// and the jQ data made for jQ event handling
jQuery.unbindall = function () { jQuery('*').unbind(); }
//
$(document).unload(function() { 
  jQuery.unbindall();
});
answered 2009-09-29T08:41:41.270

Your Answer