Open
Bug 610166
Opened 14 years ago
Updated 2 years ago
DOMMetaRemoved event can cause document to only be destroyed after two cycle collections (with event loop in between)
Categories
(Core :: DOM: Core & HTML, defect)
Tracking
()
NEW
Tracking | Status | |
---|---|---|
blocking2.0 | --- | - |
People
(Reporter: jruderman, Unassigned)
References
Details
(Keywords: testcase)
Attachments
(2 files)
1. Set nglayout.debug.disable_xul_cache to true.
2. Install 'DOM Fuzz Lite' from
https://www.squarefree.com/extensions/domFuzzLite.xpi
3. Run a debug build of Firefox like this:
XPCOM_MEM_LEAK_LOG=2 firefox u.html
4. Click the "Quit with leak check" button.
Result: during shutdown, it says "Documents: 5"
Expected: during shutdown, it should say "Documents: 4"
Reporter | ||
Comment 1•14 years ago
|
||
Reporter | ||
Comment 2•14 years ago
|
||
Something similar happens with <link rel="author"> and <link rel="help">.
Comment 3•14 years ago
|
||
Does it just happen with any display:none element?
Comment 4•14 years ago
|
||
And I assume the point is that the document doesn't leak _through_ shutdown, so normal leak logging doesn't see it?
Reporter | ||
Comment 5•14 years ago
|
||
> Does it just happen with any display:none element?
No. I tried with a display:none div.
> And I assume the point is that the document doesn't leak _through_ shutdown, so
> normal leak logging doesn't see it?
Exactly.
Why does the xul-cache matter here?
Also, if this is an easy leak to trigger, should we block on it?
How long is the document leaked? Does it leak until shutdown or until you've visited a couple of other pages?
Reporter | ||
Comment 7•14 years ago
|
||
(In reply to comment #6)
> Why does the xul-cache matter here?
The XUL cache entrains nsDocuments and doesn't listen for memory-pressure events, so it's a distraction when counting nsDocuments.
> Also, if this is an easy leak to trigger, should we block on it?
>
> How long is the document leaked? Does it leak until shutdown or until you've
> visited a couple of other pages?
I haven't figured this out. If I reload the testcase a few times, I leak more nsDocuments, but there seems to be a limit or something.
I could go for blocking. If it really is a leak, it's easy to trigger and therefore bad. If it isn't, we should still fix whatever is breaking my strategy for detecting leak-until-shutdown bugs.
blocking2.0: --- → ?
Comment 8•14 years ago
|
||
OK, two notes (Jesse, please confirm if you can):
1) The style set is not relevant. It's the _get_ of .style that matters. So
just having:
meta.style;
as the third line of the function still shows the problem.
2) If I comment out the CreateAndDispatchEvent call in
nsHTMLMetaElement::UnbindFromTree, the problem also goes away. This would
be consistent with <link showing similar issues, since <link> fires such
events.
Now the thing is... we have no DOMMetaRemoved listeners in our tree.
Comment 9•14 years ago
|
||
I added a printf to ~nsDocument to see the URIs of the documents remaining. The difference between the 8 and 9 case is that in the 9 case during shutdown we have two copis of chrome://global/content/bindings/scrollbar.xml around; in the 8 case there is only one.
And if I then breakpoint in ~nsDocument and condition it on having that URI, I see them both being destroyed off cycle collection...
If I comment out the style get, then I see the nsDocument get destroyed when the async DOM event (which holds a strong ref to the meta element) goes away.
Comment 10•14 years ago
|
||
Blocking for now since it's unclear how wide spread this is. Boris, can you dig a bit deeper here? If we learn this is unlikely to cause big problems for normal users I'm not convinced it should block, but until then...
Assignee: nobody → bzbarsky
blocking2.0: ? → final+
Updated•14 years ago
|
Priority: -- → P1
Comment 11•14 years ago
|
||
So first note: the only reason we have more than one scrollbar.xml document is that the xul proto cache is disabled..... so each scrollbar gets its own copy.
Comment 12•14 years ago
|
||
OK, I think this is invalid.
What the extension does is this:
function quitWithLeakCheck()
{
runSoon(a);
function a() { dumpln("QA"); closeAllWindows(); runOnTimer(b); dumpln("QAA"); }
function b() { dumpln("QB"); mpUntilDone(); runSoon(c); }
function c() { dumpln("QC"); bloatStats(d); }
function d(objectCounts) {
dumpln("QD");
dumpln("Windows: " + objectCounts["nsGlobalWindow"]);
dumpln("Documents: " + objectCounts["nsDocument"]);
//if (objectCounts["nsGlobalWindow"] > 4) { dumpln("OMGLEAK"); }
//if (objectCounts["nsDocument"] > 4) { dumpln("OMGLEAK"); }
runSoon(e);
}
function e() { dumpln("QE"); goQuitApplication(); }
}
where bloatStats() does an async read of about:bloat, runSoon() just posts a runnable to the main thread, and runOnTimer runs its argument after a time delay. Now the key ingredients of the testcase are:
1) A <meta> element, so that removing it from the DOM posts an nsPLDOMEvent to
the event loop which holds a strong ref to the <meta>.
2) A .style get on the <meta>, which ensures that the <meta> is in a cycle
with the nsDOMCSSAttributeDeclaration.
Now we call that function above. It closes all windows, then sets a timer to run b(). b() does a bunch of cycle collection; as a result the document containing the <meta> is destroyed, which triggers UnbindFromTree on the <meta>, which posts that nsPLDOMEvent. After this, there's a strong ref to the <meta> held by the event loop for the rest of the cycle collections, so the meta, plus anything it references, can't be collected. Then post an event to run c() and go out to the event loop, process the nsPLDOMEvent, but the <meta> is still in a cycle with its style decl, so it's not destroyed yet (in the testcase without .style the <meta> and things it entrains are destroyed here). Now c() is called, which calls bloatStats(), which synchronously (in nsAboutBloat::NewChannel) grabs the stats. There have been no cycle collections since the nsPLDOMEvent ran, so the the <meta> and things it entrains are still alive. So we see an extra xbl binding document as alive; it's destroyed the very next time we cycle collect.
Jesse, it sounds like you want to make mpUntilDone take a callback function and go back out to the event loop after each cc it does... That should make this artifact go away.
As far as causing problems for users, the only issue here is that we might need an event loop trip between two CCs to really collect everything in a document. Perhaps we should somehow flag things so the <meta> (and <link>) doesn't post the unbind event at all if the document is going away?
Comment 13•14 years ago
|
||
Thank you Boris! Given that explanation I don't think this is a blocker as it's really not a true leak, it only causes certain elements in certain cases to take more than one cc to get collected.
blocking2.0: final+ → -
Reporter | ||
Updated•14 years ago
|
Keywords: mlk
Summary: Styling <meta> leaks nsDocument until shutdown → DOMMetaRemoved event can cause document to only be destroyed after two cycle collections (with event loop in between)
Updated•14 years ago
|
Priority: P1 → P3
Comment 14•14 years ago
|
||
(In reply to comment #12)
> As far as causing problems for users, the only issue here is that we might need
> an event loop trip between two CCs to really collect everything in a document.
> Perhaps we should somehow flag things so the <meta> (and <link>) doesn't post
> the unbind event at all if the document is going away?
I think we should do this.
Comment 16•9 years ago
|
||
The issue quoted in comment 14 is, I would think, yes.
Flags: needinfo?(bzbarsky)
Assignee | ||
Updated•6 years ago
|
Component: DOM → DOM: Core & HTML
Comment 18•5 years ago
|
||
Maybe we should just add a flag to UnbindFromTree that indicates "document is being torn down" and optimize out all sorts of stuff in that case?
Priority: P5 → --
Updated•5 years ago
|
Assignee: bzbarsky → nobody
Updated•2 years ago
|
Severity: normal → S3
You need to log in
before you can comment on or make changes to this bug.
Description
•