A few days ago I landed support for per-class reporting of JavaScript objects and shapes in about:memory. (Shapes are auxiliary, engine-internal data structures that are used to facilitate object property accesses. They can use large amounts of memory.)
Prior to this patch, the JavaScript objects and shapes within a single compartment (which corresponds to a JavaScript window
or global
object) would be covered by measurements in a small number of fixed categories.
10,179,152 B (02.59%) -- objects ├───6,749,600 B (01.72%) -- gc-heap │ ├──3,512,640 B (00.89%) ── dense-array │ ├──2,965,184 B (00.75%) ── ordinary │ └────271,776 B (00.07%) ── function ├───3,429,552 B (00.87%) -- malloc-heap │ ├──2,377,600 B (00.61%) ── slots │ └──1,051,952 B (00.27%) ── elements/non-asm.js └───────────0 B (00.00%) ── non-heap/code/asm.js 474,144 B (00.12%) -- shapes ├──316,832 B (00.08%) -- gc-heap │ ├──167,320 B (00.04%) -- tree │ │ ├──152,400 B (00.04%) ── global-parented │ │ └───14,920 B (00.00%) ── non-global-parented │ ├──125,352 B (00.03%) ── base │ └───24,160 B (00.01%) ── dict └──157,312 B (00.04%) -- malloc-heap ├───99,328 B (00.03%) ── compartment-tables ├───35,040 B (00.01%) ── tree-tables ├───12,704 B (00.00%) ── dict-tables └───10,240 B (00.00%) ── tree-shape-kids
These measurements are only interesting to those who understand the guts of the JavaScript engine.
In contrast, objects and shapes are now grouped by their class. Per-class measurements relate back to the JavaScript code in a more obvious way, making these measurements useful to a wider range of people.
10,515,296 B (02.69%) -- classes ├───4,566,840 B (01.17%) ++ class(Array) ├───3,618,464 B (00.93%) ++ class(Object) ├───1,755,232 B (00.45%) ++ class(HTMLDivElement) ├─────333,624 B (00.09%) ++ class(Function) ├─────165,624 B (00.04%) ++ class(<non-notable classes>) ├──────38,736 B (00.01%) ++ class(Window) └──────36,776 B (00.01%) ++ class(CSS2PropertiesPrototype)
(The <non-notable classes>
entry aggregates all classes that are smaller than a certain threshold. This prevents any long tail of classes from bloating about:memory too much.)
Expanding the sub-tree for the Object
class, we see that the fixed categories are still present, for those who are interested in them.
3,618,464 B (00.93%) -- class(Object) ├──3,540,672 B (00.91%) -- objects │ ├──2,349,632 B (00.60%) -- malloc-heap │ │ ├──2,348,480 B (00.60%) ── slots │ │ └──────1,152 B (00.00%) ── elements/non-asm.js │ └──1,191,040 B (00.30%) ── gc-heap └─────77,792 B (00.02%) -- shapes ├──57,376 B (00.01%) -- gc-heap │ ├──47,120 B (00.01%) ── tree │ ├───5,360 B (00.00%) ── dict │ └───4,896 B (00.00%) ── base └──20,416 B (00.01%) -- malloc-heap ├──11,552 B (00.00%) ── tree-tables ├───6,912 B (00.00%) ── tree-kids └───1,952 B (00.00%) ── dict-tables
Although the per-class measurements often aren’t surprising — Object
and Array
objects and shapes often dominate — sometimes they are. Consider the following examples.
- The above example has 1.7 MiB of
HTMLDivElement
objects and shapes, which indicates that the compartment contains manydiv
elements. - If you have lots of memory used by
Function
objects and shapes, it suggests that the code is creating excessive numbers of closures. - Just this morning a visitor to the #memshrink IRC channel was wondering why they had 11 MiB of
XPC_WN_NoMods_NoCall_Proto_JSClass
objects and shapes in one compartment. (This is a question I currently don’t have a good answer for.)
Historically, the data-dependent measurements in about:memory — e.g. those done on a per-tab, or per-compartment, or per-image, or per-script basis — have been more useful and interesting than the ones in fixed categories, because they map obviously to browser and code artifacts. For example, per-tab measurements let you know if a particular web page is using excessive memory, and per-compartment measurements revealed the existence of zombie compartments, a kind of bad memory leak that used to be common in Firefox and its add-ons.
I’m hoping that these per-class measurements will prove similarly useful. Keep an eye on them, and please let me know and/or file bugs if you see any surprising cases.
A final note: Mozilla’s devtools team is currently making great progress on a JavaScript memory profiler, which will give finer-grained measurements of JavaScript memory usage in web content. Although there will be some overlap between that tool and these new measurements in about:memory, it will useful to have both tools, because each one will be appropriate in different circumstances.
2 replies on “Per-class JS object and shape measurements in Firefox’s about:memory”
Nicholas, it looks like your feed is missing from Planet Mozilla, with posts from the Mozilla Security Blog appearing under your name.
Thanks for the info. There’s a bug report filed: https://bugzilla.mozilla.org/show_bug.cgi?id=1059628.