Contents

Motivation

One of the most requested features (I think the one just after saving
CSS changes) is a support for analyzing
memory that is consumed by a web page.

Goals

A memory profiler UI should be smoothly integrated with Firebug UI (preferably linking and reusing existing UI elements) and providing such visual information that helps the user to answer/examine following questions.

What is the state of the memory consumed by the current page just now (a snapshot)?

How can I see a list of all JS objects created by the page?

How can I see relations among created objects (prototype, constructor, parent, references, referents)?

How much memory is consumed by this particular object?

Where this object has been created in the source code (url, line number)?

How to automatically execute memory profiler and compare results gathered at different moments of the page-life time?

I know there are memory leaks, how can I find them?

Are there any objects ready for garbage collecting at this moment?

Memory Profiler APIs

The currently available memory-profiler APIs allow to examine all JS objects in Firefox runtime (i.e get some meta-data for each object). It's possible to freeze it and create additional memory profiling runtime, which is consequently used to access the original Firefox runtime. There is also a way how to provide custom Javascript code that is executed within the memory profiling runtime and collect required info (see more).

Every object in a runtime is referred by a unique ID and so, the first usual thing to do is getting a list of all existing JS objects (getObjectTable). Another function (getObjectInfo allows to get a JSON-able data structure for every object according to specified ID.

The meta-data structure can contain following fields (depends on the actual JS object).

id - Unique JS object ID.

nativeClass - e.g. Function, Object, etc.

size - The total storage requirements for the object, including the (shared) memory used for property descriptors (JS_GetObjectTotalSize()).

parent (id)

prototype (id)

functionSize - Size of the function object plus size of the script (JS_GetFunctionTotalSize()).

scriptSize - Memory used to store the bytecode corresponding to the script, including things like atoms i.e. constant strings in the code (JS_GetScriptTotalSize()).

name - Name of a function (not available for instances)

filename - URL of the file where a function is defined (not available for instances).

lineStart - Line number where a function object definition begins (not available for instances).

lineEnd - Line number where a function object definition ends (not available for instances).

children - List of referred objects.

The collected data structure represents an effective graph of meta-data about all existing JS objects linked together using IDs - a snapshot of the memory state.

Missing APIs

Even if there are fields (size, functionSize, scripSize) that provide some size info, the actual number of bytes used by an object is missing. This is probably the most critical as Firebug users would probably like to see this information.

Name field is not available for simple JS objects (e.g. var o = {a:1, b:2} doesn't produce a label 'o' to be seen in the name field). These can be only recognized by a list of existing properties, which makes the association with the actual JS object on the page harder.

It would be also useful if meta-data have a field constructor, which would help to link it to the function that was used for instantiation (and consequently to the line of code where the object has been created).

One way how to get an association between a JS object existing on a page (e.g. var o = {a:1, b:2}) and meta-data structure returned by the profiler, is passing the object into profileMemory method and return it's ID. So, if all objects on the page would be collected (can be time expensive) and passed to the profiler we would have an effective mechanism how to connect returned meta-data with objects displayed in the DOM panel. It's not sure if this is a workaround of a feature, but there is apparently no other way how to get the ID for a JS object (I think JSD only allows to get a tag for script objects where the tag === id). This needs examination yet.

Memorybug

There is a working Firebug extension called Memorybug that shows what kind of information is possible to get from the current memory-profiling APIs (based on work made by Atul Varma and Dion Almer). So, far this extension is in real alpha phase.

As soon as you have all setup, load a test page and follow instructions on it.

Current UI

Memorybug plug itself into the Firebug UI as a new Memory panel.

After clicking the Memory Snapshot button, Jetpack's profileMemory function is used to get meta-data about JS objects from the Firefox runtime. The list of objects is filtered and so, only those that belongs to the current page (window) or an embedded iframe (window) are analyzed.

This screen-shot shows several groups displayed as the result of profiling. The Functions group shows all JS Functions object found on the page and its iframes. The function name is clickable and navigates the user into the Script panel.

One problem is that dynamically injected code breaks line numbers. See the next screenshot, showing what happens if the Firebug Console panel is enabled.

All functions defined on the well known console object are also visible. However these are injected dynamically by Firebug, which breaks lineStart and lineEnd data (try it with installed Memorybug).

Another screenshot shows list of JS objects found on the page together with number of instances.

Since there are no real classes in Javascript (like e.g. in C++ or Java) there is currently no way how to identify an instance, except of listing its properties and defining something called a shape.

Firebug users/developers can easily recognize the injected console object (2 instances, since there is one in an iframe) and also an object with name, age, desc properties (2 instances). The later corresponds to the following script on the page.

The last screenshot shows list of windows/iframes (URLs) with additional info for each window.

This is another approach used by [3]. Showing list of objects that are crated within specific URL also grouped by a line at which they were created. In this case 1 function object was created at line: 11 in innerFrame.html. The source code at this line is function _TestFromIframe()

Future UI

There are surely better ways how to integrate the memory-profiling feature with the rest of Firebug UI (i.e. the other panels) and also better ways how to present all gathered information to the user. But limited by the power of available APIs.

Following list summarizes some ideas:

There should be a new console.memoryProfile() method that allows to automated profiling. The result info can be logged directly into the Console panel similarly to what console.profileStart and console.profileEnd methods do.

The Dom panel should displays number of raw bytes consumed for every displayed object (such number would be available as soon as the profiler has been launched).

The Memory panel should also support a Persist feature (like Net and Console panels) and archive memory-snapshots made at different times within the page life cycle (both manual or automatic profiling should be respected). In such a case the history should allow to see how the memory consumption increased/decreased.

Every JS object appearing in memory-profiling results should be linked with the Script panel showing it's location in the source and also linked with the DOM panel showing the location in DOM hierarchy.

Finally, similarly to the Net panel, it should be possible to export all the info into a file.