Closed Bug 677949 Opened 10 years ago Closed 6 years ago

Need a way to find GC roots


(Core :: JavaScript Engine, defect)

Not set





(Reporter: sfink, Unassigned)




(1 file, 1 obsolete file)

When tracking down a "zombie compartment" bug, I found it very helpful to dump out the GC roots for a compartment. We should just have a debug call to do exactly that.

In fact, I don't see why this couldn't be made available via Components.utils as a pure-JS operation. Then you could do hunt zombies in the chrome Web Console.
WIP patch that adds a findRoots call which takes either the codebase of a compartment or the hex address (for distinguishing multiple [System Principal] compartments.) It returns an array of the named GC roots for the compartment.

This is early work that I'm putting on the shelf for now. It does not yet give the names of the roots (which are available in DEBUG builds for many of them.) A number of the roots don't have a toString so you can't tell much about what they are. I intend to add descriptive containers for each one instead of just returning the raw values. This should also return things rooted by cross-compartment wrappers and other (?) holders.

I'm putting this here for now because I think it's useful in its current form.
This is still a mess, probably a bigger mess, but it's giving me useful information. In addition to the named root scanning, which is still there, this now also scans the entire JS heap and records every object in the compartment. I don't really want it to do this, but for zombie compartments it may not be too bad. (For example, in my current Firebug case, this reports exactly 4 objects. Which isn't bad.)

This patch also stops returning the actual values. Now they are only described by name and pointer. This is because I suspect that when you run this from the Web Console, it remembers the return value in its history and so adds additional roots. Not helpful.

Example output:

WebConsole> Components.utils.findRoots("")
[{name:"global object", pointer:"0x7fffd417c028"},
{name:"nsXPCWrappedJS[nsIDOMEventListener,0x7fffd0b9e800:0x7fffd0b2eb60].mJSObj", pointer:"0x7fffd0aaee48"},
{name:"mScopeObject", pointer:"0x7fffd4175088"},
{name:"mScopeObject", pointer:"0x7fffd4175088"}]
(gdb) p ((nsXPCWrappedJS*)0x7fffd0b9e800)->mJSObj
$80 = 0x7fffd0aaee48 [Object Function "fireContentLoadedEvent"] COMPARTMENT(principals=0x7fffda6b7828 "")

(The gdb output is with archer-mozilla, including an uncommitted 'set print js-compartments on' from my local tree.)

So apparently a listener for a "ContentLoadedEvent" is lurking around, keeping the whole nytimes compartment alive.

Oh, wait. I lied. It was only 4 objects because I had closed the nytimes tab before it finished loading. After a full load, there are 49 objects in the compartment, and although the above nsIDOMEventListener is in the list, there are a lot of other nsIDOMEventListener objects that are not so easy to dissect. Oh well, too much is still better than too little, for now.
Attachment #552123 - Attachment is obsolete: true
Assignee: general → nobody
This has been subsumed by the GC heap graph dumping.
Closed: 6 years ago
Resolution: --- → WONTFIX
You need to log in before you can comment on or make changes to this bug.