We are using YUI’s onclick events, but we create and delete dome nodes rapidly and this leads to memory leak.
Consider this example code below, We have many 3 nested divs many times. The top and the bottom div have YUI onclick events attached. What is the proper way to get rid of those dom elements and not leak memory:
I’m really out of any ideas. As you can see I tried implementing our own destroy function. Actually destroy works and does not leak, but it is slow.
The destroy2 function is ‘copy’ of the YUI destroy function where we used to debug what is the problem. It looks like the recursive clean up of YUI can not find the child nodes in the _instances dictionary
<!DOCTYPE html5>
<html>
<head>
<script src="http://yui.yahooapis.com/3.4.1/build/yui/yui-min.js"></script>
</head>
<body>
<div id="main">hi there</div>
<script>
YUI().use("node", "event", function(Y) {
window.Y = Y;
function destroy(node) {
(new Y.Node(node)).destroy();
var children = node.children;
for (var i = 0; i<children.length; i++) {
destroy(children[i]);
}
}
function destroy2(node, recursive) {
var UID = Y.config.doc.uniqueID ? 'uniqueID' : '_yuid';
// alert(1);
if (recursive) {
var all = node.all("*");
// alert(all);
Y.NodeList.each(all, function(n) {
instance = Y.Node._instances[n[UID]];
// alert(instance);
if (instance) {
destroy2(instance);
}
});
}
node._node = null;
node._stateProxy = null;
delete Y.Node._instances[node._yuid];
// node.destroy();
}
var main = new Y.Node("#main");
var divs = [];
var iter = 0;
Y.later(10, window, function() {
iter ++ ;
var i;
for (i=0; i<divs.length; i++) {
var d = divs[i];
d.parentNode.removeChild(d);
// (new Y.Node(d)).destroy(true);
//destroy(d);
//destroy2(new Y.Node(d), true);
(new Y.Node(d)).destroy(true);
}
divs = [];
for (i=0; i<1000; i++) {
var d = document.createElement("div");
var i1;
var i2;
d.appendChild(i1=document.createElement("div"));
i1.appendChild(document.createTextNode('inner 1'));
i1.appendChild(i2=document.createElement("div"));
i2.appendChild(document.createTextNode('inner 2'));
Y.on("click", function() {
alert("inner click")
}, i2);
// try to tell YUI to make Node elements
Y.Node.one(d);
Y.Node.one(i1);
Y.Node.one(i2);
// new Y.Node(d);
// new Y.Node(i1);
// new Y.Node(i2);
d.appendChild(document.createTextNode("this is div " + iter + " " + i));
Y.on("click", function(){ alert("you clicked me");}, d);
main.appendChild(d);
//divs.push(i2);
divs.push(d);
}
}, null, true);
})
</script>
</body>
</html>
Here is what I ended up doing to avoid the memory leaks:
I have to say I’m very disapointed by the YUI documentation that says this for the YUI destroy function.
I kind of consider this bug in YUI because it does not call recursively purge when you call destroy recursively. Also it looks like the above destroy function is very slow on Firefox 8 (maybe other versions too) I did write my own recursion down the dom tree and called
purgeand
destroywithouttrue.