mozilla
Your Search Results

    Tools/Debugger-API/Debugger.Memory

    Debugger.Memory

    The Debugger API can help tools observe the debuggee’s memory use in various ways:

    • It can mark each new object with the JavaScript call stack at which it was allocated.

    • It can log all object allocations, yielding a stream of JavaScript call stacks at which allocations have occurred.

    • It can compute a census of items belonging to the debuggee, categorizing items in various ways, and yielding item counts.

    If dbg is a Debugger instance, then the methods and accessor properties of dbg.memory control how dbg observes its debuggees’ memory use. The dbg.memory object is an instance of Debugger.Memory; its inherited accesors and methods are described below.

    Allocation Site Tracking

    The JavaScript engine marks each new object with the call stack at which it was allocated, if:

    • the object is allocated in the scope of a global object that is a debuggee of some Debugger instance dbg; and

    • dbg.memory.trackingAllocationSites is set to true.

    Given a Debugger.Object instance dobj referring to some object, dobj.allocationSite returns a saved call stack indicating where dobj’s referent was allocated.

    Allocation Logging

    If dbg is a Debugger instance, and dbg.memory.trackingAllocationSites is set to true, then the JavaScript engine logs each object allocated by dbg’s debuggee code. You can retrieve the current log by calling dbg.memory.drainAllocationsLog. You can control the limit on the log’s size by setting dbg.memory.maxAllocationsLogLength.

    Censuses

    A census is a complete traversal of the graph of all reachable memory items belonging to a particular Debugger‘s debuggees. It produces a count of those items, broken down by various criteria. If dbg is a Debugger instance, you can call dbg.memory.takeCensus to conduct a census of its debuggees’ possessions.

    Accessor Properties of the Debugger.Memory.prototype Object

    If dbg is a Debugger instance, then <i>dbg</i>.memory is a Debugger.Memory instance, which inherits the following accessor properties from its prototype:

    trackingAllocationSites

    A boolean value indicating whether this Debugger.Memory instance is capturing the JavaScript execution stack when each Object is allocated. This accessor property has both a getter and setter: assigning to it enables or disables the allocation site tracking. Reading the accessor produces true if the Debugger is capturing stacks for Object allocations, and false otherwise. Allocation site tracking is initially disabled in a new Debugger.

    Assignment is fallible: if the Debugger cannot track allocation sites, it throws an Error instance.

    You can retrieve the allocation site for a given object with the Debugger.Object.prototype.allocationSite accessor property.

    maxAllocationsLogLength

    The maximum number of allocation sites to accumulate in the allocations log at a time. This accessor can be both fetched and stored to. Its default value is 5000.

    Function Properties of the Debugger.Memory.prototype Object

    drainAllocationsLog()

    When trackingAllocationSites is true, this method returns an array of recent Object allocations within the set of debuggees. Recent is defined as the maxAllocationsLogLength most recent Object allocations since the last call to drainAllocationsLog. Therefore, calling this method effectively clears the log.

    Objects in the array are of the form:

    
    {
      "timestamp": timestamp,
      "frame": allocationSite
    }
    

    Here timestamp is the timestamp of the event in units of microseconds since the epoch and allocationSite is an allocation site (as a captured stack). allocationSite is null for objects allocated with no JavaScript frames on the stack.

    When trackingAllocationSites is false, drainAllocationsLog() throws an Error.

    takeCensus()

    Carry out a census of the debuggee compartments’ contents. A census is a complete traversal of the graph of all reachable memory items belonging to a particular Debugger’s debuggees. The census produces a count of those items, broken down by various criteria.

    The takeCensus method returns an object of the form:

    
    {
      "objects": { class: tally, ... },
      "scripts": tally,
      "strings": tally,
      "other": { type name: tally, ... }
    }
    

    Each tally has the form:

    
    { "count": count }
    

    where count is the number of items in the category.

    The "objects" property’s value contains the tallies of JavaScript objects, broken down by their ECMAScript [[Class]] internal property values. Each class is a string.

    The "scripts" property’s value tallies the in-memory representation of JavaScript code.

    The "strings" property’s value tallies the debuggee’s strings.

    The "other" property’s value contains the tallies of other items used internally by SpiderMonkey, broken down by their C++ type name.

    Because performing a census requires traversing the entire graph of objects in debuggee compartments, it is an expensive operation. On developer hardware in 2014, traversing a memory graph containing roughly 130,000 nodes and 410,000 edges took roughly 100ms. The traversal itself temporarily allocates one hash table entry per node (roughly two address-sized words) in addition to the per-category counts, whose size depends on the number of categories.

    Memory Use Analysis Exposes Implementation Details

    Memory analysis may yield surprising results, because browser implementation details that are transparent to content JavaScript often have visible effects on memory consumption. Web developers need to know their pages’ actual memory consumption on real browsers, so it is correct for the tool to expose these behaviors, as long as it is done in a way that helps developers make decisions about their own code.

    This section covers some areas where Firefox’s actual behavior deviates from what one might expect from the specified behavior of the web platform.

    Objects

    SpiderMonkey objects usually use less memory than the naïve “table of properties with attributes” model would suggest. For example, it is typical for many objects to have identical sets of properties, with only the properties’ values varying from one object to the next. To take advantage of this regularity, SpiderMonkey objects with identical sets of properties may share their property metadata; only property values are stored directly in the object.

    Array objects may also be optimized, if the set of live indices is dense.

    Strings

    SpiderMonkey has three representations of strings:

    • Normal: the string’s text is counted in its size.

    • Substring: the string is a substring of some other string, and points to that string for its storage. This representation may result in a small string retaining a very large string. However, the memory consumed by the string itself is a small constant independent of its size, since it is simply a reference to the larger string, a start position, and a length.

    • Concatenations: When asked to concatenate two strings, SpiderMonkey may elect to delay copying the strings’ data, and represent the result simply as a pointer to the two original strings. Again, such a string retains other strings, but the memory consumed by the string itself is a small constant independent of its size, since it is simply a pair of pointers.

    SpiderMonkey converts strings from the more complex representations to the simpler ones when it pleases. Such conversions usually increase memory consumption.

    SpiderMonkey shares some strings amongst all web pages and browser JS. These shared strings, called atoms, are not included in censuses’ string tallies.

    Scripts

    SpiderMonkey has a complex, hybrid representation of JavaScript code. There are four representations kept in memory:

    • Source code. SpiderMonkey retains a copy of most JavaScript source code.

    • Compressed source code. SpiderMonkey compresses JavaScript source code, and de-compresses it on demand. Heuristics determine how long to retain the uncompressed code.

    • Bytecode. This is SpiderMonkey’s parsed representation of JavaScript. Bytecode can be interpreted directly, or used as input to a just-in-time compiler. Source is parsed into bytecode on demand; functions that are never called are never parsed.

    • Machine code. SpiderMonkey includes several just-in-time compilers, each of which translates JavaScript source or bytecode to machine code. Heuristics determine which code to compile, and which compiler to use. Machine code may be dropped in response to memory pressure, and regenerated as needed.

    Furthermore, SpiderMonkey tracks which types of values have appeared in variables and object properties. This type information can be large.

    In a census, all the various forms of JavaScript code are placed in the "script" category. Type information is accounted to the "types" category.

    Source Metadata

    Generated from file:
    js/src/doc/Debugger/Debugger.Memory.md
    Watermark:
    sha256:83230ada5b76fe9b924b4bcb500434d7ae9317d08053fa0d038b18f5142b97ba
    Changeset:
    b8098ac8ea6e

    Document Tags and Contributors

    Contributors to this page: jimblandy
    Last updated by: jimblandy,