Matt Kruse wrote:
Richard Cornford wrote:
>The global object has a property named 'menu' that refers
to the DOM element with the ID "menu", the LI elements
that have the event handlers are descendants of the
element with the ID "menu" and so will be referred to
through its childNodes, firstChild and lastChild
properties (though possibly through a number of
intervening elements). The LI elements refer to the
event handling functions and the event handling functions
have the global object on their scope chains (that is,
their scope chains refer to the global object).
Ah, I see. So in theory, attaching event handlers to
_any_ object that has an ID could cause a problem in
IE because a function defined anywhere will have the
global object in its scope, and therefore a reference
to the object being attached to, causing the circular
reference?
The theory that says 'all circular references including DOM nodes causes
the memory leak issue' certainly would carry that implication (and worse
as the global object has a - document - property that refers to the
document, and the child relationships in the DOM link every element form
the document, so any event handler with the global object on its scope
chain would form a circular reference regardless of its having an IE).
Has this been proven in a simple example?
Now that is a very good question, and I don't think I have ever seen
this aspect of the issue demonstrated. It turns out that there is a very
good reason for that.
I've not seen any references to this specific problem
in my reading about IE's memory leaks.
I have seen it mentioned on quirksmode at least once.
I'm still not clear where these references "live" for
IE, since previous discussions hint that there is a
hidden layer in IE's scope chain for things like this.
No evidence has been presented do support that suggestion. The symptoms
observed are amenable to simpler explanation (and without a
discriminating test Ockam's razor favours the simpler explanation).
So does that still cause a leak? Time to
fire up Drip...
Drip may be better than nothing (what it does identify is significant),
but it does not identify all leak scenarios.
Now, to the actual testing of the issues related to IDed elements, and
circular references through the global object into the document; there
is not real issue. The theory that all circular references between DOM
nodes and javascript objects cause memory leaks in IE is insufficient as
an explanation of what happens.
Because the DOM is a tree Nodes will refer to their childbed, and their
children to their parents. As a result there must be circular references
all over the palace when event handlers are assigned to Elements by
scripts.
I resurrected my original leak testing scripts; the ones that oscillate
between a 'leaky' page and a normal page. Setting those pages up such
that event handlers were assigned to IDed elements showed no leaking
resulting form the references to the global object on the event
handler's scope chain.
Thinking about this I was forced to conclude that the circular
references must have been being broken by the browser itself. I
suspected that the references being removed would be the parent/child
references in the DOM, as IE could do that automatically as it unloads a
page.
To test that specific idea I set up a closure based leak scenario as
follows:-
window.onload = function(){
var el = anId; // where a Element has the ID "anId"
el.onclick = function(){
return true;
}
el.onclick.balast = getBigString(); // getBigString returns an 8
// Megabyte string which makes
// any leak very obvious.
};
This code steady leaks memory as the test script oscillates between this
page and the other page, because of the Node-Node.onclick ->
Node.onclick.[[Scope]] -Node circular reference.
Nulling the - el - variable:-
window.onload = function(){
var el = anId; // where a Element has the ID "anId"
el.onclick = function(){
return true;
}
el.onclick.balast = getBigString(); // getBigString returns an 8
// Megabyte string which makes
// any leak very obvious.
el = null;
};
- breaks the circle and prevents the leak.
Now, suppose instead of nulling - el - a reference to el.parentNode was
assigned:-
window.onload = function(){
var el = anId; // where a Element has the ID "anId"
el.onclick = function(){
return true;
}
el.onclick.balast = getBigString(); // getBigString returns an 8
// Megabyte string which makes
// any leak very obvious.
el = el.parentNode;
};
In theory we have a circular reference Node-Node.onclick ->
Node.onclick.[[Scope]] -Node.parentNode -Node, but this arrangement
does not leak. The only differnce between this and the first leaking
example is that the reference to the DOM node on the event handlers
scope chain (via the - el - local variable) has been replaced by a
reference to its parentNode. There is a circular reference but no leak
happens, and the only point at which the circle could be broken is the
reference between the parenNode and its child.
A similar experiment putting a child of the Node on the event handler's
scope chain had a similar result, with no leak being observed.
My conclusion has to be that IE explicitly breaks all inter DOM Node
references as it unloads pages. Thus circular references that include
these references are _not_ significant to the memory leak issue.
The IE leak theory should be clarified along the lines of 'Circular
references between DOM nodes and JS objects cause memory leaks so long
as no reference in that circle is a parent/child reference from the
DOM'.
As far as your original question goes, I neglected to test whether
NodeLIst (and/or NamedNodeMap) objects are treated like DOM nodes. I may
get round to that in the next few days.
Richard.