Bug 148158 - Web Inspector: DOMTree leaks on main resource changes
Summary: Web Inspector: DOMTree leaks on main resource changes
Status: RESOLVED FIXED
Alias: None
Product: WebKit
Classification: Unclassified
Component: Web Inspector (show other bugs)
Version: WebKit Nightly Build
Hardware: All All
: P2 Normal
Assignee: Joseph Pecoraro
URL:
Keywords: InRadar
Depends on:
Blocks: 148223
  Show dependency treegraph
 
Reported: 2015-08-18 18:48 PDT by Joseph Pecoraro
Modified: 2015-08-20 09:26 PDT (History)
8 users (show)

See Also:


Attachments
[PATCH] Proposed Fix (5.19 KB, patch)
2015-08-19 17:52 PDT, Joseph Pecoraro
no flags Details | Formatted Diff | Diff

Note You need to log in before you can comment on or make changes to this bug.
Description Joseph Pecoraro 2015-08-18 18:48:07 PDT
* SUMMARY
DOMTree leaks on main resource changes.

* NOTES
- DOMTree registers itself as a listener on DOMTreeManager during construction:
    WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.DocumentUpdated, this._documentUpdated, this);
    WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.ContentFlowListWasUpdated, this._contentFlowListWasUpdated, this);
    WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.ContentFlowWasAdded, this._contentFlowWasAdded, this);
    WebInspector.domTreeManager.addEventListener(WebInspector.DOMTreeManager.Event.ContentFlowWasRemoved, this._contentFlowWasRemoved, this);
    - However, these are never removed. So that means the DOMTree, and everything it hangs onto (DOMNodes) will remain alive.

- Perhaps "invalidate" should be removing these event listeners. Needs a bit more investigation.
Comment 1 Radar WebKit Bug Importer 2015-08-18 18:48:35 PDT
<rdar://problem/22337238>
Comment 2 Joseph Pecoraro 2015-08-19 12:51:56 PDT
After studying the ownership of different DOM* objects, this is what I think:

  1. Frame's own DOMTrees which register DOMTreeManager listeners
    => when a Main Frame is replaced, each frame in the frame three should "disconnect" their DOMTree
    => when a Sub Frame is removed, it should "disconnect" its DOMTree

  2. DOMContentViews registers DOMTreeManager listeners
    => already "disconnects" its listeners when the ContentView is closed

  3. DOMContentViews own DOMTreeOutlines which register DOMTreeManager listeners
    => already informs its DOMTreeUpdater to "disconnect" when the ContentView is closed

So the issue here is only a `Frame <-> DOMTree <-> DOMTreeManager listener` leak. Though that could leak a bunch of Resources because the DOMTree references the Frame.
Comment 3 Joseph Pecoraro 2015-08-19 17:52:29 PDT
Created attachment 259436 [details]
[PATCH] Proposed Fix

After testing this keeps the number of WebInspector.domTreeManager event listeners down to 2 after navigating / reloading, and ending up on a simple page.
Comment 4 Devin Rousso 2015-08-19 18:51:30 PDT
Comment on attachment 259436 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=259436&action=review

> Source/WebInspectorUI/UserInterface/Models/DOMTree.js:90
> +            this._invalidateTimeoutIdentifier = undefined;

Lack of knowledge question:  is there a reason to use "undefined" here instead of "null"?  As I understood it, timeout id's are just integers...

> Source/WebInspectorUI/UserInterface/Models/Frame.js:449
> +    _detachFromParentFrame()

NIT: It looks weird to me to see non-"this" objects calling a private method (seen on lines 334 and 345 above).  I would make this public so it doesn't look so weird...
Comment 5 Timothy Hatcher 2015-08-19 20:25:46 PDT
Comment on attachment 259436 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=259436&action=review

>> Source/WebInspectorUI/UserInterface/Models/DOMTree.js:90
>> +            this._invalidateTimeoutIdentifier = undefined;
> 
> Lack of knowledge question:  is there a reason to use "undefined" here instead of "null"?  As I understood it, timeout id's are just integers...

It will start as undefined until the timeout is used the first time. Though 0 would be fine too, we just tend to use undefined here.

>> Source/WebInspectorUI/UserInterface/Models/Frame.js:449
>> +    _detachFromParentFrame()
> 
> NIT: It looks weird to me to see non-"this" objects calling a private method (seen on lines 334 and 345 above).  I would make this public so it doesn't look so weird...

It is still internal to this class, so it is fine.
Comment 6 WebKit Commit Bot 2015-08-19 21:09:23 PDT
Comment on attachment 259436 [details]
[PATCH] Proposed Fix

Clearing flags on attachment: 259436

Committed r188679: <http://trac.webkit.org/changeset/188679>
Comment 7 WebKit Commit Bot 2015-08-19 21:09:27 PDT
All reviewed patches have been landed.  Closing bug.
Comment 8 Joseph Pecoraro 2015-08-19 21:35:50 PDT
Comment on attachment 259436 [details]
[PATCH] Proposed Fix

View in context: https://bugs.webkit.org/attachment.cgi?id=259436&action=review

>>> Source/WebInspectorUI/UserInterface/Models/DOMTree.js:90
>>> +            this._invalidateTimeoutIdentifier = undefined;
>> 
>> Lack of knowledge question:  is there a reason to use "undefined" here instead of "null"?  As I understood it, timeout id's are just integers...
> 
> It will start as undefined until the timeout is used the first time. Though 0 would be fine too, we just tend to use undefined here.

I have been using "undefined" or "false" for primitives that were deleted. Technically 0 or NaN would be okay here, but I don't want to confuse that with an actual number.
I have been using "null" for objects / arrays that were deleted. That should make it clear that an object occupies this property.