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 many div 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.