lsc*_*lt2 6 jquery memory-leaks internet-explorer-9 firefox4
我一直在使用jQuery在所有主流浏览器中遇到一些内存泄漏,我正在寻找一些帮助.我读过很多关于内存泄漏,引用,循环引用,闭包等的文章.我想我做的一切都是正确的.但我仍然看到IE9和FF4中的内存增加以及sIEve中的孤儿对我来说没有意义.
我已经创建了一个测试用例来展示这个问题.测试用例基本上有一个500行的大表,用户可以点击每一行进入内联编辑模式,其中使用jQuery追加元素.当用户退出内联编辑模式时,将删除元素.
测试用例有一个按钮可模拟100行100次点击以快速放大问题.
当我在sIEve中运行它时,内存增加1600KB,使用量增加506,并且有99个孤儿.有趣的是,如果我在第123行注释掉.remove(),内存增加1030KB,使用量增加11,并且有0个孤儿.
当我在IE9中运行它时,内存增加5900KB.刷新再增加1500KB,另一次运行增加1K.继续这种模式继续增加内存使用
当我在FF4中运行它时,如果我使用"100次点击缓慢"和"100次快速点击",我会得到非常不同的行为.模拟慢速点击的峰值增加了8300KB,它需要一分钟才能达到3300KB.模拟快速点击的峰值增加了27,700KB,然后需要一分钟才能达到4700KB.请注意,这与执行的代码完全相同,执行之间的延迟更少.刷新和另一次运行继续以类似的速率增加内存.
示例代码:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Strict//EN">
<html>
<head>
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.6.1/jquery.min.js"></script>
<script type="text/javascript">
var clickcounter = 0;
var clickdelay = 0;
var clickstart = 0;
var clicklimit = 0;
$(document).ready(function(){
// Create a table with 500 rows
var tmp = ['<table>'];
for (var i = 0; i < 500; i++) {
tmp.push('<tr id="product_id',i+1,'" class="w editable">');
tmp.push('<td class="bin">',i+1,'</td>');
tmp.push('<td class="productcell" colspan="2">Sample Product Name<div class="desc"></div></td>');
tmp.push('<td class="percentcost">28%</td>');
tmp.push('<td class="cost">22.50</td>');
tmp.push('<td class="quantity">12</td>');
tmp.push('<td class="status">Active</td>');
tmp.push('<td class="glass">23</td>');
tmp.push('<td class="bottle">81</td>');
tmp.push('</tr>');
}
tmp.push('</table>');
$('body').append(tmp.join(''));
// Live bind a click event handler to enter Inline Edit
$('tr.w').live('click', function(event){
var jrow = $(this);
if (!jrow.find('.inedBottle').length) {
createInlineEdit(jrow);
}
});
// This is just to emulate 100 clicks on consecutive rows
$('#slow100').click(function() {
clickstart = clickcounter;
clickcounter++;
var jrow = $('#product_id'+clickcounter);
createInlineEdit(jrow);
clickdelay = 1000;
clicklimit = 100;
window.setTimeout(clickemulate, clickdelay);
});
// This is just to emulate 100 rapid clicks on consecutive rows
$('#fast100').click(function() {
clickstart = clickcounter;
clickcounter++;
var jrow = $('#product_id'+clickcounter);
createInlineEdit(jrow);
clickdelay = 20;
clicklimit = 100;
window.setTimeout(clickemulate, clickdelay);
});
});
// Emulate clicking on the next row and waiting the delay period to click on the next
function clickemulate() {
if ((clickcounter - clickstart) % clicklimit == 0) return;
nextInlineEdit($('#product_id'+ clickcounter));
clickcounter++;
window.setTimeout(clickemulate, clickdelay);
}
// Enter inline edit mode for the row
function createInlineEdit(jrow, lastjrow) {
removeInlineEdit(lastjrow);
jrow.removeClass('editable').addClass('editing');
// Find each of the cells
var productcell = jrow.find('.productcell');
var bincell = jrow.find('.bin');
var percentcostcell = jrow.find('.percentcost');
var costcell = jrow.find('.cost');
var glasscell = jrow.find('.glass');
var bottlecell = jrow.find('.bottle');
var descdiv = productcell.find('.desc');
var product_id = jrow.attr('id').replace(/^product_id/,'');
// Replace with an input
bincell.html('<input class="inedBin" name="bin'+product_id+'" value="'+bincell.text()+'">');
costcell.html('<input class="inedCost" name="cost'+product_id+'" value="'+costcell.text()+'">');
glasscell.html('<input class="inedGlass" name="glass'+product_id+'" value="'+glasscell.text()+'">');
bottlecell.html('<input class="inedBottle" name="bottle'+product_id+'" value="'+bottlecell.text()+'">');
var tmp = [];
// For one input, insert a few divs and spans as well as the inputs.
// Note: the div.ined and the spans and input underneath are the ones remaining as orphans in sIEve
tmp.push('<div class="ined">');
tmp.push('<span>Inserted Span 1</span>');
tmp.push('<span>Inserted Span 2</span>');
tmp.push('<input class="inedVintage" name="vintage',product_id,'" value="">');
tmp.push('<input class="inedSize" name="size',product_id,'" value="">');
tmp.push('</div>');
tmp.push('<div class="descinner">');
tmp.push('<input class="inedDesc" name="desc'+product_id+'" value="'+descdiv.text()+'">');
tmp.push('</div>');
descdiv.html(tmp.join(''));
jrow.find('.inedVintage').focus().select();
}
// Exit the inline edit mode
function removeInlineEdit(jrow) {
if (jrow && jrow.length) {
} else {
jrow = $('tr.w.editing');
}
jrow.removeClass('editing').addClass('editable');
// Note: the div.ined and the spans and input underneath are the ones remaining as orphans in sIEve
// sIEve steps: load page, click "Clear in use", click "100 clicks fast" on the page
// If the remove is commented out, then sIEve does not report any div.ined as orphans and reports 11 in use (div.ined all appear to be garbage collected)
// If the remove is uncommented, then sIEve reports 99 of the div.ined as orphans and reports 506 in use (none of the div.ined garbage collected)
jrow.find('.ined').remove();
jrow.find('.inedBin').each(function() {
$(this).replaceWith(this.defaultValue);
});
jrow.find('.inedGlass').each(function() {
$(this).replaceWith(this.defaultValue);
});
jrow.find('.inedBottle').each(function() {
$(this).replaceWith(this.defaultValue);
});
jrow.find('.inedCost').each(function() {
$(this).replaceWith(this.defaultValue);
});
jrow.find('.inedDesc').each(function() {
// Since the div.ined is under here, this also removes it.
$(this).closest('.desc').html(this.defaultValue);
});
}
function nextInlineEdit(jrow) {
var nextjrow = jrow.nextAll('tr.w').first();
if (nextjrow.length) {
createInlineEdit(nextjrow, jrow);
} else {
removeInlineEdit(jrow);
}
}
</script>
<style>
table {margin-top: 30px;}
td {border: 1px dashed grey;}
button#slow100 {position: fixed; left: 0px; width: 115px;}
button#fast100 {position: fixed; left: 120px; width: 115px;}
</style>
</head>
<body>
<button id="slow100">100 clicks slow</button>
<button id="fast100">100 clicks fast</button>
</body>
</html>
Run Code Online (Sandbox Code Playgroud)
小智 -1
也许 1 个问题可能是 .live 的使用。我不确定 .live 内部是如何工作的,但它必须侦听更改 DOM 的事件(每次更新/替换 td 中的元素时,如果有新元素,<td class="w">它会使用给定的回调来观察它)。如果 .live 方法尚未准备好检查$("td.w")DOM 中包含的另一个方法,并且您开始另一次检查,则可能会导致内存泄漏。我只是猜测,但尝试替换此代码:
$('tr.w').live('click', function(event){
var jrow = $(this);
if (!jrow.find('.inedBottle').length) {
createInlineEdit(jrow);
}
});
Run Code Online (Sandbox Code Playgroud)
有了这个:
$('tr.w').bind('click', function(event){
var jrow = $(this);
if (!jrow.find('.inedBottle').length) {
createInlineEdit(jrow);
}
});
Run Code Online (Sandbox Code Playgroud)
在繁重的 DOM 操作过程中,您的内存使用率可能会越来越低。让我知道这是否有帮助!
| 归档时间: |
|
| 查看次数: |
1236 次 |
| 最近记录: |