JavaScript Tracing
The following are example scripts for tracing JavaScript using the Mozilla DTrace provider.
Example Scripts
These scripts have been writen to trace activity from all browsers on the system that support the Mozilla DTrace provider; to trace single browser instances, modify the scripts to match the provider "javascript$target" and run the scripts with "-p PID" as the argument.
A feature of DTrace is that the browser does not need to be restarted for DTrace to work. The JavaScript probes cause zero overhead until they are enabled by a DTrace script, and tracing begins.
Example Target: clock.html
This simple JavaScript clock will be run as the target for the tracing demonstrations that follow,
<HTML>
<HEAD>
<TITLE>Clock, JavaScript</TITLE>
<SCRIPT type="text/javascript">
function padZero(i)
{
if (i < 10) return "0" + i;
return i;
}
function startTime()
{
var now = new Date;
var time = padZero(now.getHours()) + ":" +
padZero(now.getMinutes()) + ":" +
padZero(now.getSeconds());
document.getElementById('clock').innerHTML = "time: " + time + "<br>";
var timeout = setTimeout('startTime()', 1000);
}
</SCRIPT>
</HEAD>
<BODY onload="startTime()">
<DIV id="clock"></DIV>
</BODY>
</HTML>
js_funccalls.d
This is a simple script to count the number of JavaScript function calls while the script was running.
#!/usr/sbin/dtrace -Zs
/*
* js_funccalls.d - measure JavaScript function calls using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_calls.d # hit Ctrl-C to end
*
* FIELDS:
* FILE Filename that contained the function
* FUNC JavaScript function name
* CALLS Function calls during this sample
*
* Filename and function names are printed if available, else "<null>".
*/
#pragma ident "@(#)js_funccalls.d 1.3 07/03/26 SMI"
#pragma D option quiet
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
}
javascript*:::function-entry
{
@funcs[basename(copyinstr(arg0)), copyinstr(arg2)] = count();
}
dtrace:::END
{
printf(" %-32s %-36s %8s\n", "FILE", "FUNC", "CALLS");
printa(" %-32s %-36s %@8d\n", @funcs);
}
Example output,
# ./js_funccalls.d Tracing... Hit Ctrl-C to end. ^C FILE FUNC CALLS nsMicrosummaryService.js GetSources 1 nsMicrosummaryService.js MSS__getBookmarks 1 nsMicrosummaryService.js MSS__updateMicrosummaries 1 nsMicrosummaryService.js getPref 1 nsMicrosummaryService.js getPrefType 1 nsMicrosummaryService.js getService 1 nsMicrosummaryService.js hasMoreElements 1 nsMicrosummaryService.js max 1 nsMicrosummaryService.js now 1 nsMicrosummaryService.js GetResource 2 nsMicrosummaryService.js MSS__resource 2 clock.html getElementById 3 clock.html getHours 3 clock.html getMinutes 3 clock.html getSeconds 3 clock.html setTimeout 3 clock.html startTime 3 clock.html padZero 9
Apart from events from clock.html, the script also traced some events from the browser.
js_funcinfo.d
This script is similar to js_funccalls.d, however prints additional call information which is especially useful for tracing anonymous functions,
# ./js_funcinfo.d Tracing... Hit Ctrl-C to end. ^C BASE[FILE:LINE] FUNCNAME RUN[FILE:LINE] CALLS clock2.html:7 getElementById clock2.html:12 1 clock2.html:7 getHours clock2.html:9 1 clock2.html:7 getMinutes clock2.html:10 1 clock2.html:7 getSeconds clock2.html:11 1 clock2.html:7 setTimeout clock2.html:13 1 clock2.html:7 startTime clock2.html:13 1 clocklib.js:2 padLibZero clock2.html:10 1 clocklib.js:2 padLibZero clock2.html:11 1 clocklib.js:2 padLibZero clock2.html:9 1
The "BASE" details show where the function was declared or first used; the "RUN" info shows where the function was executed.
js_funcflow.d
This script traces the flow of JavaScript functions, by indenting as a function is entered and un-indenting as the function completes.
#!/usr/sbin/dtrace -Zs
/*
* js_funcflow.d - snoop JavaScript function execution using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_funcflow.d # hit Ctrl-C to end
*
* This watches JavaScript function entries and returns, and indents child
* function calls. For busy JavaScript, the output will be very verbose.
*
* FIELDS:
* C CPU-id
* TIME Time of function call
* FILE Filename that this function belongs to
* FUNC JavaScript function name
*
* Filename and function names are printed if available, else "<null>".
*
* WARNING: Watch the first column carefully, it prints the CPU-id. If it
* changes, then it is very likely that the output has been shuffled.
*/
#pragma ident "@(#)js_funcflow.d 1.3 07/03/26 SMI"
#pragma D option quiet
#pragma D option switchrate=10
dtrace:::BEGIN
{
depth = 0;
printf("%s %-20s %-22s ~-- %s\n", "C", "TIME", "FILE", "FUNC");
}
javascript*:::function-entry
{
depth++;
printf("%d %-20Y %-22s %*s-> %s\n", cpu, walltimestamp,
basename(copyinstr(arg0)), depth*2, "", copyinstr(arg2));
}
javascript*:::function-return
{
printf("%d %-20Y %-22s %*s<- %s\n", cpu, walltimestamp,
basename(copyinstr(arg0)), depth*2, "", copyinstr(arg2));
depth~--;
}
Running this script while clock.html runs produces,
# ./js_funcflow.d C TIME FILE ~-- FUNC 0 2007 Mar 26 16:42:09 clock.html -> startTime 0 2007 Mar 26 16:42:09 clock.html -> getHours 0 2007 Mar 26 16:42:09 clock.html <- getHours 0 2007 Mar 26 16:42:09 clock.html -> padZero 0 2007 Mar 26 16:42:09 clock.html <- padZero 0 2007 Mar 26 16:42:09 clock.html -> getMinutes 0 2007 Mar 26 16:42:09 clock.html <- getMinutes 0 2007 Mar 26 16:42:09 clock.html -> padZero 0 2007 Mar 26 16:42:09 clock.html <- padZero 0 2007 Mar 26 16:42:09 clock.html -> getSeconds 0 2007 Mar 26 16:42:09 clock.html <- getSeconds 0 2007 Mar 26 16:42:09 clock.html -> padZero 0 2007 Mar 26 16:42:09 clock.html <- padZero 0 2007 Mar 26 16:42:09 clock.html -> getElementById 0 2007 Mar 26 16:42:09 clock.html <- getElementById 0 2007 Mar 26 16:42:09 clock.html -> setTimeout 0 2007 Mar 26 16:42:09 clock.html <- setTimeout 0 2007 Mar 26 16:42:09 clock.html <- startTime 0 2007 Mar 26 16:42:10 clock.html -> startTime 0 2007 Mar 26 16:42:10 clock.html -> getHours 0 2007 Mar 26 16:42:10 clock.html <- getHours 0 2007 Mar 26 16:42:10 clock.html -> padZero 0 2007 Mar 26 16:42:10 clock.html <- padZero 0 2007 Mar 26 16:42:10 clock.html -> getMinutes 0 2007 Mar 26 16:42:10 clock.html <- getMinutes 0 2007 Mar 26 16:42:10 clock.html -> padZero 0 2007 Mar 26 16:42:10 clock.html <- padZero 0 2007 Mar 26 16:42:10 clock.html -> getSeconds 0 2007 Mar 26 16:42:10 clock.html <- getSeconds 0 2007 Mar 26 16:42:10 clock.html -> padZero 0 2007 Mar 26 16:42:10 clock.html <- padZero 0 2007 Mar 26 16:42:10 clock.html -> getElementById 0 2007 Mar 26 16:42:10 clock.html <- getElementById 0 2007 Mar 26 16:42:10 clock.html -> setTimeout 0 2007 Mar 26 16:42:10 clock.html <- setTimeout 0 2007 Mar 26 16:42:10 clock.html <- startTime ^C
The execution of the clock.html script can be seen. This tool isn't as useful as it may appear - serious JavaScript applications will produce hundreds of pages of output per second. Perhaps this is more useful as a demonstration of DTrace capabilities.
js_functime.d
The following script traces elapsed times for JavaScript functions. Elapsed is the time from the function entry to the return, and may include other JavaScript functions and time the JavaScript spent off the CPU. If you'd prefer other ways to calculate time spent in functions, hack away...
#!/usr/sbin/dtrace -Zs
/*
* js_functime.d - measure JavaScript function times using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_functime.d # hit Ctrl-C to end
*
* FIELDS:
* FILE Filename that contained the function
* FUNCTION JavaScript function name
* COUNT Number of calls during this sample
* AVG(us) Average function elapsed time, us
* SUM(us) Total function elapsed time, us
*
* This measures the elapsed times for function entries to returns, and
* provides some aggregated statistics. Be aware that the elapsed time for
* a function is overlapping; it includes the elapsed times for child
* functions that it called.
*
* Filename and function names are printed if available, else "<null>".
*/
#pragma ident "@(#)js_functime.d 1.3 07/03/26 SMI"
#pragma D option quiet
this string str;
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
depth = 0;
}
javascript*:::function-entry
{
self->depth++;
self->start[copyinstr(arg2), self->depth] = timestamp;
}
javascript*:::function-return
/(this->str = copyinstr(arg2)) != NULL && self->start[this->str, self->depth]/
{
this->file = basename(copyinstr(arg0));
this->elapsed = timestamp - self->start[this->str, self->depth];
@num[this->file, this->str] = count();
@eavg[this->file, this->str] = avg(this->elapsed);
@esum[this->file, this->str] = sum(this->elapsed);
@edist[this->str] = quantize(this->elapsed);
self->start[this->file, self->depth] = 0;
self->depth~--;
}
dtrace:::END
{
normalize(@eavg, 1000);
normalize(@esum, 1000);
printf("ELAPSED TIME DISTRIBUTION,\n");
printa(@edist);
setopt("aggsortpos", "2");
printf("%-33s %45s\n", "{{{___}}} OVERLAP TIMES: {{{___}}}",
"{{{______}}} ELAPSED {{{_____}}}");
printf("%-24s %-23s %6s %10s %12s\n", "FILE", "FUNCTION",
"COUNT", "AVG(us)", "SUM(us)");
printa("%-24.24s %-23.23s %@6d %@10d %@12d\n", @num, @eavg, @esum);
}
Example output,
# ./js_functime.d
Tracing... Hit Ctrl-C to end.
^C
ELAPSED TIME DISTRIBUTION,
getMinutes
value ~------------- Distribution ~------------- count
2048 | 0
4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
8192 | 0
getSeconds
value ~------------- Distribution ~------------- count
2048 | 0
4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
8192 | 0
getHours
value ~------------- Distribution ~------------- count
8192 | 0
16384 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
32768 | 0
padZero
value ~------------- Distribution ~------------- count
2048 | 0
4096 |@@@@@@@@@@@@@@@@@@@@@@@@@@@ 6
8192 |@@@@@@@@@@@@@ 3
16384 | 0
getElementById
value ~------------- Distribution ~------------- count
16384 | 0
32768 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
65536 | 0
setTimeout
value ~------------- Distribution ~------------- count
16384 | 0
32768 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
65536 | 0
startTime
value ~------------- Distribution ~------------- count
262144 | 0
524288 |@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ 3
1048576 | 0
{{{___}}} OVERLAP TIMES: {{{___}}} {{{______}}} ELAPSED {{{_____}}}
FILE FUNCTION COUNT AVG(us) SUM(us)
clock.html getSeconds 3 6 20
clock.html getMinutes 3 7 22
clock.html padZero 9 7 64
clock.html getHours 3 26 78
clock.html getElementById 3 44 132
clock.html setTimeout 3 51 155
clock.html startTime 3 975 2925
The example output shows that the slowest function was startTime, which isn't suprising as startTime contains all the other function calls. The slowest individual function was setTimeout with 3 calls at an average elapsed time of 51 microseconds per call; and the fastest function was getSeconds, which was called 3 times at an average of 6 microseconds per call.
Care must be taken when using a tool like this to fully understand how the time measurements are taken, and what conclusions can and can't be made based on the output.
js_objs.d
This script snoops (traces) JavaScript object creation,
#!/usr/sbin/dtrace -Zs
/*
* js_objs.d - snoop JavaScript Object creation using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_objs.d # hit Ctrl-C to end
*
* FIELDS:
* TIME Time string
* FILE Filename that contained the function
* LINENO File line number where object was created
* CLASS Class to which this new object belongs
*
* Filename and class names are printed if available, else "<null>".
*/
#pragma ident "@(#)js_objs.d 1.3 07/03/26 SMI"
#pragma D option quiet
dtrace:::BEGIN
{
printf("%-20s %24s:%-7s %s\n", "TIME", "FILE", "LINENO", "CLASS");
}
javascript*:::object-create
/arg2/
{
printf("%-20Y %24.24s:%-7d %s\n", walltimestamp,
basename(copyinstr(arg0)), (int)arg3, copyinstr(arg1));
}
Example output,
# ./js_objs.d TIME FILE:LINENO CLASS 2007 Mar 26 18:31:31 clock.html:13 Date 2007 Mar 26 18:31:32 clock.html:13 Date 2007 Mar 26 18:31:33 clock.html:13 Date 2007 Mar 26 18:31:34 clock.html:13 Date 2007 Mar 26 18:31:35 clock.html:13 Date 2007 Mar 26 18:31:36 clock.html:13 Date ^C
In the above output, several Date objects were created by line 13 of clock.html.
The following example output traces JavaScript activity by the browser interface (triggered by clicking on plugins and menus),
# ./js_objs.d TIME FILE:LINENO CLASS 2007 Mar 26 18:36:22 clock.html:13 Date 2007 Mar 26 18:36:22 <null>:-1 Event 2007 Mar 26 18:36:22 <null>:-1 Function 2007 Mar 26 18:36:22 <null>:-1 Function 2007 Mar 26 18:36:22 <null>:-1 MouseEvent 2007 Mar 26 18:36:22 browser.xul:1 Call 2007 Mar 26 18:36:22 utilityOverlay.js:380 Function 2007 Mar 26 18:36:22 sb-loader.js:161 XULElement 2007 Mar 26 18:36:22 sb-loader.js:167 XPCWrappedNative_NoHelper 2007 Mar 26 18:36:22 <null>:-1 Function 2007 Mar 26 18:36:22 sb-loader.js:168 Function 2007 Mar 26 18:36:22 utilityOverlay.js:387 nsJSCID 2007 Mar 26 18:36:22 utilityOverlay.js:388 nsJSIID 2007 Mar 26 18:36:22 utilityOverlay.js:388 XPCWrappedNative_NoHelper 2007 Mar 26 18:36:22 nsUpdateService.js:1593 Function 2007 Mar 26 18:36:22 nsUpdateService.js:1593 XPC_WN_NoMods_Proto_JSClass 2007 Mar 26 18:36:22 nsUpdateService.js:1593 nsXPCComponents_Interfaces 2007 Mar 26 18:36:22 nsUpdateService.js:1593 nsJSIID 2007 Mar 26 18:36:22 utilityOverlay.js:388 XPCWrappedNative_NoHelper 2007 Mar 26 18:36:22 nsUpdateService.js:1593 Function 2007 Mar 26 18:36:22 nsUpdateService.js:1594 nsJSIID 2007 Mar 26 18:36:22 nsUpdateService.js:1595 nsJSIID 2007 Mar 26 18:36:22 nsUpdateService.js:1596 nsJSIID 2007 Mar 26 18:36:22 utilityOverlay.js:388 XPCWrappedNative_NoHelper [...]
Sometimes the filename and line number are not available, and so "<null>" and -1 are printed to indicate this.
js_objnew.d
This is a simple script to summarize the number of new objects created,
#!/usr/sbin/dtrace -Zs
/*
* js_objnew.d - measure JavaScript new objects using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_objnew.d # hit Ctrl-C to end
*
* FIELDS:
* FILE Filename that contained the function
* CLASS Class to which this new object belongs
* COUNT Number of objects created
*
* Filename and class names are printed if available, else "<null>".
*/
#pragma ident "@(#)js_objnew.d 1.3 07/03/26 SMI"
#pragma D option quiet
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
}
javascript*:::object-create
{
@objs[basename(copyinstr(arg0)), copyinstr(arg1)] = count();
}
dtrace:::END
{
printf(" %-24s %-36s %8s\n", "FILE", "CLASS", "COUNT");
printa(" %-24.24s %-36s %@8d\n", @objs);
}
Example output,
# ./js_objnew.d Tracing... Hit Ctrl-C to end. ^C FILE CLASS COUNT clock.html Date 6
Example "noisy" output,
# ./js_objnew.d Tracing... Hit Ctrl-C to end. ^C FILE CLASS COUNT browser.xul Call 2 menu.xml Array 2 sb-loader.js Function 2 sb-loader.js XPCWrappedNative_NoHelper 2 utilityOverlay.js Function 2 nsUpdateService.js Array 4 bookmarks.js Error 6 clock.html Date 6 nsUpdateService.js XPCWrappedNative_NoHelper 6 popup.xml Array 9 browser.js Function 18 menu.xml XPCWrappedNative_NoHelper 20 nsUpdateService.js Function 22 <null> MouseEvent 28 <null> Event 84 menu.xml XULElement 120 <null> Function 231
js_objcpu.d
Sometimes the CPU time consumed to create new objects can be a performance issue. This simple script measures that time,
#!/usr/sbin/dtrace -Zs
/*
* js_objcpu.d - measure JavaScript Object create on-CPU time using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_objcpu.d # hit Ctrl-C to end
*
* This measures the on-CPU time consumed due to JavaScript Object creation.
*/
#pragma ident "@(#)js_objcpu.d 1.3 07/03/26 SMI"
#pragma D option quiet
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
}
javascritp*:::object-create-start
{
self->vstart = vtimestamp;
}
javascript*:::object-create-done
/self->vstart/
{
this->oncpu = vtimestamp - self->vstart;
@dist["Object Creation on-CPU time (ns):"] = quantize(this->oncpu);
@total["Total on-CPU time (us):"] = sum(this->oncpu);
self->vstart = 0;
}
dtrace:::END
{
normalize(@total, 1000);
}
Example output,
# ./js_objcpu.d
Tracing... Hit Ctrl-C to end.
^C
Object Creation on-CPU time (ns):
value ~------------- Distribution ~------------- count
256 | 0
512 |@@@@@@@@@ 92
1024 |@@@@@@@@@@@@@@@@@@@@@@@@ 235
2048 |@@@@ 36
4096 |@ 13
8192 |@@ 19
16384 | 0
32768 | 1
65536 | 0
Total on-CPU time (us): 824
js_objgc.d
The following script is useful to check the behaviour of garbage collect. It tallys the number of objects and prints a summary every second. By watching the output for a while (several minutes or more), steadily increasing object counts into the thousands may be evidence of an object leak.
#!/usr/sbin/dtrace -Zs
/*
* js_objgc.d - measure JavaScript Object GC using DTrace.
* Written for the Solaris Mozilla DTrace provider.
*
* This traces JavaScript activity from all running browers on the system
* which support the mozilla DTrace provider.
*
* USAGE: js_objgc.d # hit Ctrl-C to end
*
* FIELDS:
* FILE Filename that contained the function
* CLASS Class to which this new object belongs
* TOTAL Object entropy (positive == uncollected)
*
* This script provides information on which objects are not being garbage
* collected, an issue which causes the browser to steadily leak memory.
* We trace object creation (+1) and destruction (-1), and provide a
* summary each second of the running tally of the object class and
* originating filename. If over the period of several minutes an object
* type is still steadily increasing, then that would be of interest.
* Be patient, depending on the rate of object creation, it can take over
* ten minutes for garbage collect to kick in.
*
* Filename and class names are printed if available, else "<null>".
*
* NOTE: there are other Things that GC handles, other than Objects; extra
* probes can be added to trace them, should the need arise.
*/
#pragma ident "@(#)js_objgc.d 1.3 07/03/26 SMI"
#pragma D option quiet
#pragma D option dynvarsize=32m
dtrace:::BEGIN
{
printf("Tracing... Hit Ctrl-C to end.\n");
}
javascript*:::object-create
/arg2/
{
this->file = basename(copyinstr(arg0));
@objs[this->file, copyinstr(arg1)] = sum(1);
filename[arg2] = this->file;
}
javascript*:::object-finalize
/filename[arg2] == NULL/
{
/* these are caused by dynvardrops. increase dynvarsize */
@objs["<missed>", copyinstr(arg1)] = sum(-1);
}
javascript*:::object-finalize
/filename[arg2] != NULL/
{
@objs[filename[arg2], copyinstr(arg1)] = sum(-1);
filename[arg2] = 0;
}
profile:::tick-1sec,
dtrace:::END
{
printf("\n %-24s %-36s %8s\n", "FILE", "CLASS", "TOTAL");
printa(" %-24.24s %-36s %@8d\n", @objs);
}
Example output,
# ./js_objgc.d Tracing... Hit Ctrl-C to end. FILE CLASS TOTAL fastclock.html Date 88 FILE CLASS TOTAL fastclock.html Date 173 FILE CLASS TOTAL fastclock.html Date 259 FILE CLASS TOTAL fastclock.html Date 345 FILE CLASS TOTAL nsMicrosummaryService.js Array 1 nsMicrosummaryService.js Function 3 nsMicrosummaryService.js XPCWrappedNative_NoHelper 4 fastclock.html Date 431 [...time passes...] FILE CLASS TOTAL <null> MouseEvent 1 browser.js Array 1 browser.js CSSStyleDeclaration 1 browser.js ComputedCSSStyleDeclaration 1 browser.js XPCNativeWrapper 1 browser.xul XPCNativeWrapper 1 popup.xml Array 1 browser.js Constructor 2 browser.js XPC_WN_ModsAllowed_Proto_JSClass 2 nsMicrosummaryService.js Array 4 nsMicrosummaryService.js Function 6 nsMicrosummaryService.js XPCWrappedNative_NoHelper 7 <null> Function 14 browser.js Function 17 fastclock.html Date 5321 FILE CLASS TOTAL <missed> Function -172 <missed> Date -152 <missed> XPCWrappedNative_NoHelper -33 <missed> Object -19 <missed> Attr -15 <missed> Array -14 <missed> Call -8 <missed> XPC_WN_NoMods_Proto_JSClass -7 <missed> BarProp -6 <missed> BoxObject -1 <missed> HTMLDivElement -1 <missed> Iterator -1 <missed> NamedNodeMap -1 <missed> XULElement -1 <null> MouseEvent 0 browser.js Array 0 browser.js CSSStyleDeclaration 0 browser.js ComputedCSSStyleDeclaration 0 browser.js XPCNativeWrapper 0 nsMicrosummaryService.js Array 0 nsMicrosummaryService.js Function 0 nsMicrosummaryService.js XPCWrappedNative_NoHelper 0 popup.xml Array 0 browser.xul XPCNativeWrapper 1 fastclock.html HTMLDivElement 1 browser.js Constructor 2 browser.js XPC_WN_ModsAllowed_Proto_JSClass 2 <null> Function 3 browser.js Function 6 fastclock.html Date 7
In the above output, the Date object from fastclock.html steadily increased until there were 5321 of them, then the following output shows that the Date object count has dropped to 7 - this shows garbage collect working. Also in the final output are many negative count objects with a "<missed>" filename - these are objects that were already in memory when tracing began (so their count was zero), and we traced their destruction (so they count became negative).