Background: Inspired by this question and this question about D3 memory usage I decided to dig into how it really works, and soon came upon cautions about repeated add/remove of DOM nodes in IE.
To isolate from whatever else D3 was doing, I first tried the basic SVG case of adding/removing 1000 circles every second:
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);
I found that this slowly leaks memory in both IE9 and IE10. See here for live version: http://bl.ocks.org/explunit/6413259
What (if anything) can I do to prevent the leak, and what implications does this have for how D3 code targeting IE should be written that adds/removes a lot of nodes?
Other notes:
Inspired by this article, I tried a simple node pool approach by pushing the removed nodes on to a stack:
if (parent) circlePool.push( parent.removeChild(circles[i]) );
And reusing them later:
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
}
But this did not make any difference.