具有 ID 属性的动态 DOM 对象的 IE9 内存泄漏
我注意到为动态创建的 DOM 对象分配 ID 属性值会导致 IE9 内存泄漏。有其他人经历过这种情况,更重要的是,知道任何解决方法吗?在其他浏览器中不漏,连IE6也通过!
泄漏代码演示:
它只是不断地从表中添加和删除行,并为每行分配一个 ID 以供稍后查找。
如果没有“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>
我注意到从表行中删除所有单元格会导致内存泄漏缩小,因此我猜 IE 在从表中删除该行后仍会保留该行。
我还尝试了一种解决方法,将创建的表行添加到 Javascript 对象中以用作哈希表,而不是依赖 getElementById(row.id) ,但由于某种我看不到的原因,该方法也泄漏了。
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];
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];
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
我在我的案例中找到了一个合适的解决方案,注意到在“运行”一段时间后重新加载包含的测试页会导致内存使用量暂时保持不变(相对于重新加载之前运行的时间)。之后又开始上涨。
所以,看起来,是的,IE 在删除元素后并没有完全删除 ID:d 元素使用的资源,但如果再次将相同的 ID 添加到页面,它显然会重新使用这些资源。
因此,只需确保添加和删除的 ID 是有限集合的一部分,而不是无限集合的一部分。测试页使用严格递增的基于整数的 ID,而我最初的问题案例使用类似的序列号 ID。幸运的是,在这两种情况下都很容易将它们固定在有限的范围内。
对于上面的测试代码:
++count;
如果(计数 > 1000)计数 = 0;
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;
早在我使用 Java Swing 的时候(是的,我老了),JVM 也有类似的问题。因为垃圾收集器无法清理嵌套在其他 Swing 对象中的 Swing 对象,从而导致内存泄漏。
我过去常常通过将每个 Swing 对象显式设置为 NULL 来解决这个问题,因为它们不再需要了。
对于深层嵌套对象(即包含其他 Swing 对象的 Swing 表),我编写了一个可由所有 Swing 类使用的递归方法,该方法将向下遍历任何 Swing 对象,对其中找到的每个对象进行 NULL 处理。
令人恼火的是,我必须付出所有这些额外的努力才能解决 JVM 垃圾收集器中的错误,但它运行得非常好。一旦我做到了这一点,内存泄漏就消失了。
在 IE9 上尝试类似的东西可能值得尝试。强制 DOM 对象为 NULL,因为它们不再需要,可以为您解决这个问题。我们其他人也是如此......:-)
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... :-)