Niklas Bäckman
Niklas Bäckman

Reputation: 466

IE9 memory leak for dynamic DOM objects with ID attribute

I've noticed that assigning the ID attribute a value to dynamically created DOM objects causes IE9 to leak memory. Has anyone else experienced this, and more importantly, know of any work-arounds? It does not leak in other browsers, even IE6 passes!

Demonstration of leak code:

It simply adds and removes rows from a table continuously and assigns an ID to each row to be used for lookup later.

No leak occurs without "row.id = eid;"

    <html>
    <head>
        <script type="text/javascript">

        function addRow(tbl, index) {
            var row = tbl.insertRow(index);
            var eid = "loongrowid" + count;
            row.id = eid;

            for (var i = 0; i < 9; i++) {
                row.insertCell(i);
            }

            return row;
        }

        function removeTableRow(tbl, index) {
            var row = tbl.rows[index];
            tbl.deleteRow( index );

        }

        var count = 1;

        function fillRow(row){
            row.cells[0].innerHTML = '<input type="checkbox"' + ' checked="checked"' + ' />';
            for (var i = 1; i < 9; i++) { 
                row.cells[i].innerHTML = count + " c";
            }
            ++count;
        }

        var added = false;

        function dostuff() 
        {
            var tbl = document.getElementById("tbl");
            var i;

            if (added)
            {
                for (i = 0; i < 20; ++i)
                {
                    removeTableRow(tbl,1);
                }
            }
            else
            {
                for (i = 0; i < 20; ++i)
                {
                    var row = addRow(tbl, i+1);
                    fillRow(row);
                }
            }

            added = !added;
            setTimeout(dostuff, 1); 
        }
        </script>
    </head>
    <body onload="setTimeout(dostuff, 1)">
    <h1 id="count">TESTING</h1>
    <table id="tbl" style="width:100%;">    
    <tr>
        <th>selected</th>
        <th>date</th>
        <th>time</th>
        <th>place</th>
        <th>device</th>
        <th>text</th>
        <th>state</th>          
        <th>status</th>
        <th>quality</th>
    </tr>
    </table>
    </body>
</html>

I noticed that removing all cells from the table row causes the memory leak to shrink, so I guess IE holds on to the row after its been removed from the table.

I also tried a work-around that added the created table rows into an Javascript object to be used as a hash-table instead of relying on getElementById(row.id) but that also leaked for some reason I cannot see.

var hash = [];

    // when creating row
    row.extid = eid; // Note: this by itself causes no leak
hash[eid] = row; 

    // when removing row
delete hash[row.extid]; 

Upvotes: 6

Views: 2214

Answers (2)

Niklas B&#228;ckman
Niklas B&#228;ckman

Reputation: 466

I found a suitable solution in my case by noticing that reloading the included test page after it had been "running" for a while caused the memory usage to stay constant temporarily (relative to the time it had been running before reload). After that it started rising again.

So, it seems that, yes, IE does not remove the resources used by ID:d elements completely after the element is removed, but it will apparently re-use those resources if the same ID is added to the page again.

Ergo, just make sure that the IDs being added and removed are part of a limited set and not an unbounded one. The test page uses strictly increasing integer-based IDs and my original problem case used similar sequence number IDs. Luckily it's quite easy to fix them to a limited range in both cases.

For the test code above:

++count; if (count > 1000) count = 0;

Upvotes: 2

Bob FiveThousand
Bob FiveThousand

Reputation: 137

Back in my Java Swing days (yeah yeah, I'm old), the JVM had a somewhat similar problem. In that the Garbage Collector would fail to clean up Swing objects that were nested inside of other Swing Objects and thus cause a memory leak.

I used to get around this by explicitly setting every Swing object to NULL as they were no longer needed.

In the case of deeply nested objects (ie. Swing Tables containing other Swing Objects), I wrote a recursive method that could be used by all of my Swing classes which would traverse down through any Swing object, NULL-ing every object found within.

It was irritating that I had to go through all this extra effort just to work around a bug in the JVM's Garbage Collector, but it worked beautifully. Once I had this in place, the memory leaks vanished.

It might be worth the experiment of trying something similar with IE9. Forcing DOM objects to NULL as they are no longer needed, may solve this for you. And the rest of us as well... :-)

Upvotes: 0

Related Questions