user408346
user408346

Reputation: 86

Adding DOM elements with jquery append() appears to leak memory?

Just met with a customer who have huge memory leak issues in their Ajax webapp. So I decided to create the following testcase to demonstrate the problem:

I have used drip / Sieve for memory profiling in the example below (http://home.orange.nl/jsrosman/)

The case is simple: I have the following javascript:

<html>
    <head>    
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js">
</script>    
</head>    
<script type="text/javascript">

    var lihtml = "<li class='green'>this is a test text</li>";

    function populatelist() {
        for (var i = 0; i < 10000; i++) {
            $('#listparent').append(lihtml);
        }    
    }    

    function clearlist() {
        $('#listparent').empty();
        if (typeof (CollectGarbage) == "function") {
            alert('gc');
            CollectGarbage();
        }    
    } 


    /* Alternative clearlist with Remove instead of Empty(), still leaks */
    function clearlist() {
        /* test remove the parent itself instead of empty below */
        $('#listparent').remove();
        $('body').append("<ul id='listparent'>");        
        //$('#listparent').empty();
        if (typeof (CollectGarbage) == "function") {
            alert('gc');
            CollectGarbage();
        }
    }

   /* Edit!, this is the most effective way to release memory so far */
   function clearlist() {
    $('#listparent').html("");
    if (typeof (CollectGarbage) == "function") {
        alert('gc');
        CollectGarbage();
    }
}
</html>   
</script>

<body>
    <button onclick="javascript:populatelist()">Populate list</button>
    <button onclick="javascript:clearlist()">Clear list</button>
    <ul id="listparent">
        <li>kjjk</li>
    </ul>    
</body>

</html>

Each click on populate list appends 10000 li elements (represented as text). Clearlist calls jquery empty() which supposedly should clear the DOM subtree and make it eligible for GC.

So I run this case in sIEve and for each time I append new elements the memory usage increases, I have never seen it garbage collect or free memory. Not even when the RAM usage reaches 1.5GB and even though I try calling GC explicitly for IE.

This is the same sympton I saw at the customer who used Jquery Ajax for the List data instead of my static content obv.

Am I creating the DOM in the wrong way ? Can anybody tell me why it isn't garbage collected, I can't see any other references to the DOM elements as to why they shouldnt be garbage collected. Another weird behaviour is that sometimes in sIEve memory usage even increase when I click empty list (when jquery empty() method is being called) ?

If anybody has input I would be VERY happy.

UPDATE, I tried using $('#listparent').html("") instead which seems to release the DOM correctly, at least it is being released in sIEve. I guess that's the best solution so far though I have no explanation to why remove() and empty() doesn't seem to work. Maybe they only work for statically added elements ?

Upvotes: 6

Views: 3955

Answers (3)

user408346
user408346

Reputation: 86

$('#listparent').html(""); 

works where neither empty() or remove() did. I wish I knew why. I guess it's a solution though.

/* This is the most effective way to release memory so far */

function clearlist() {
    $('#listparent').html("");
    if (typeof (CollectGarbage) == "function") {
        alert('gc');
        CollectGarbage();
    }

Upvotes: 0

fcalderan
fcalderan

Reputation:

yes you could make an huge improvement doing smthg like so

var lihtml = "<li class='green'>this is a test text</li>",
    listring = "";

function populatelist() {
        for (var i = 0; i < 10000; i++) {
            listring += lihtml;
        }    

        $('#listparent').append(listring);

    }    
...

limit DOM access as few as possible.

The difference is that you make 1 single append instead of 10 thousands appends. You always need to avoid DOM manipulation inside cycles

Edit: instead of empty() your ul have you tried to remove() the ul and then suddenly re-create it?

Upvotes: 1

Luca Matteis
Luca Matteis

Reputation: 29267

I suggest appending to the HTML string and then adding it to the DOM:

function populatelist() {
    for (var i = 0; i < 10000; i++) {
        //$('#listparent').append(lihtml);
        lihtml += "<li class='green'>this is a test text</li>";
    }    
}    
populateList();
$('#listparent').append(lihtml);

Upvotes: 1

Related Questions