5

背景:受这个问题这个关于 D3 内存使用的问题的启发,我决定深入研究它是如何工作的,很快就发现了关于在 IE 中重复添加/删除 DOM 节点的警告

为了与 D3 所做的其他事情隔离开来,我首先尝试了每秒添加/删除 1000 个圆圈的基本 SVG 案例:

var count = 1000;
var svg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
svg.setAttribute('width', '800');
svg.setAttribute('height', '800');
document.body.appendChild(svg);

function update() {
  // remove existing circles
  var circles = svg.querySelectorAll("circle")
  for (var i = circles.length - 1; i >= 0; i--) {
    var parent = circles[i].parentNode;
    if (parent) parent.removeChild(circles[i]);
  };

  // add new ones. Yes, would make more sense to update the x,y on the existing
  // circles but this is to show what happens in IE with lots of nodes being added/removed
  for (var j = count - 1; j >= 0; j--) {
    var node = document.createElementNS("http://www.w3.org/2000/svg", 'circle');
    node.id = 'id' + Math.random();
    node.setAttributeNS(null, "cx", Math.random()*800);
    node.setAttributeNS(null, "cy", Math.random()*800);
    node.setAttributeNS(null, "r",  5);
    node.setAttributeNS(null, "fill", "blue");
    svg.appendChild(node);
  };
}

setInterval(update, 1000);

我发现这会在 IE9 和 IE10 中缓慢泄漏内存。现场版本见这里:http: //bl.ocks.org/explunit/6413259

我可以做些什么(如果有的话)来防止泄漏,这对如何编写针对 IE 的 D3 代码添加/删除大量节点有什么影响?

其他注意事项:

这篇文章的启发,我尝试了一种简单的节点池方法,将移除的节点推送到堆栈中:

if (parent) circlePool.push( parent.removeChild(circles[i]) );

并在以后重用它们:

var node;
if (circlePool.length == 0) {
  node = document.createElementNS("http://www.w3.org/2000/svg", 'circle');
} else {
  node = circlePool.pop();
  //TODO: clear out attributes of the node
}

但这没有任何区别。

4

1 回答 1

2

到目前为止,我发现唯一有助于 IE 内存使用的方法是为节点分配 ID,或者为它们分配在动画迭代中重复的 ID:

node.id = 'id' + j;

在此处查看实时版本:http: //bl.ocks.org/explunit/6413371

我认为在删除 DOM 节点之前清空 ID 会做同样的事情,但这没有效果。

我不太喜欢这个答案,所以我希望其他人能更好地解释为什么节点池方法不起作用。

但就目前而言,对于使用 D3 的开发人员来说,故事的寓意是:如果您反复添加然后删除大量具有唯一 ID 的节点(例如,从 .ajax 调用中获取记录),您可能处于危险之中内存泄漏。

于 2013-09-02T14:26:19.883 回答