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 ?
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);
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?
$('#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();
}
精彩评论