Analyzing memory usage data (JavaScript)

This topic describes the JavaScript Memory Analyzer. This tool is available for Windows Store apps built using JavaScript in Visual Studio 2012 Update 1. For a tutorial showing how to use the tool, see Tutorial: Finding a memory leak (JavaScript).

You can use the JavaScript Memory Analyzer when you have a working Windows Store app open in Visual Studio.

To run the JavaScript Memory Analyzer

  1. If you are running the app from Visual Studio, click Local Machine, Simulator, or Remote Machine in the Start Debugging drop-down list on the Debug toolbar.

    For more info about these options, see Running Windows Store apps from Visual Studio.

  2. On the Debug menu, point to JavaScript Analysis, then Memory, and then click one of these:

    • Launch Startup Project. Click this option to start the current startup project. If you're running the app on a remote machine, you must click this option.

    • Launch Installed App Package. Click this option to select an installed app that you want to analyze. This option is not supported when running the app on a remote machine.

      You can use this option to analyze memory usage of apps that you have installed on your computer when you don't have access to source code. This option can also be useful when you just want to analyze the memory usage of any app, outside of your own app development.

    • Attach to Running App. Click this option to select the app from a list of running apps. This option is not supported when running the app on a remote machine.

      You can use this option to analyze memory usage of apps that are running on your computer when you don't have access to source code.

    When you start the memory analyzer, you might see a User Account Control requesting your permission to run VsEtwCollector.exe. Click Yes.

  3. Switch to Visual Studio by pressing Alt+Tab.

    The summary view for the JavaScript Memory Analyzer appears in Diagnostics hub tab.

When you run the JavaScript Memory Analyzer, these views of memory usage data are available:

  • Summary View . Provides a memory usage graph for the running app and a collection of all snapshot summary tiles. This view appears in the Diagnostics hub tab.

  • Snapshot details . Shows detailed memory usage data for a single snapshot.

  • Snapshot diff . Shows detailed memory usage data as differential values between two selected snapshots.

The summary view provides a memory usage graph for the running app and a collection of all the snapshot summary tiles. In this view, you can perform basic tasks like taking snapshots, analyzing summary information, and navigating to other views.

The memory graph shows you a live view of the app's process memory, which includes private bytes, native memory, and the JavaScript heap. Here's what the graph looks like:

JavaScript Memory Analyzer memory graph

The memory graph is a scrollable view of the process memory.

If any profile marks have been added to the app code, a User Mark triangle will appear in the memory usage graph to indicate when that section of code is reached. For more info, see JavaScript Console Commands.

Some memory shown in the memory graph is allocated by the JavaScript runtime. You can't control this memory usage in your app. The memory usage shown in the graph increases when you take your first snapshot, and then it increases more minimally for each additional snapshot.

You can take a snapshot of the current state of the app's memory usage by clicking Take Heap Snapshot in the summary view. A snapshot summary tile, which also appears in the summary view, provides information about the JavaScript heap and links to more detailed information. If you have two or more snapshots taken, a snapshot provides additional information comparing its data to that of the previous snapshot.

Note Note

The JavaScript Memory Analyzer forces a garbage collection before each snapshot. This helps to ensure that results are more consistent among runs.

This illustration shows an example of a snapshot when a previous snapshot has been taken.

Snapshot summary

This is the information that appears in the snapshot summary:

  • Snapshot title and the timestamp.

  • Heap size (blue text, left side). This number includes DOM elements and objects that the JavaScript runtime engine adds to the JavaScript heap. The heap size is a link to the Dominators view of the snapshot.

  • Differential heap size (red or green text, left side). This value shows the difference between the heap size of the current snapshot and that of the previous snapshot. The value shows in red if there is a memory increase; otherwise, it shows in green. If the heap size is the same, the value is No Diff. For the first snapshot, the value is simply Baseline (gray text). This value is a link to the Dominators view of the snapshot diff.

  • Object count (blue text, right side). This count shows only objects created in your app, and filters out built-in objects created by the JavaScript runtime. The object count links to the Types view of the snapshot details.

  • Differential object count (red or green text, right side). This value shows the difference between the object count of the current snapshot and that of the previous snapshot. The value shows in red if there is an increase in the object count; otherwise, it shows in green. If the object count is the same, the value is No Diff. For the first snapshot, the value is simply Baseline (gray text). This value is a link to the Types view of the snapshot diff.

  • Screenshot of the screen at the time the snapshot is taken.

Tip Tip

It is possible that a snapshot summary shows no increase or a negative size/count difference, but could still hide a memory leak. That can happen when the number/size of newly created objects is less than number/size of objects that have been deleted. For example, this could happen as a result of a garbage collection.

You can view detailed information about memory usage for each snapshot in the snapshot details view.

From the summary view, you can view the snapshot details by clicking a link in a snapshot summary. For example, the heap size link in a snapshot summary opens the snapshot details, with the Dominators view open by default.

This illustration shows the Types view in a snapshot detail.

Snapshot details view showing types

In the snapshot details view, these additional views of memory usage data are available:

  • Dominators. Shows a list of all objects that are in the heap, sorted by retained size.

  • Types. Shows the instance count and total size of objects, grouped by object type. By default, these are sorted by instance count.

  • Roots. Shows a tree of objects from the root objects through child references. By default, the child nodes are sorted by the retained size column, with the largest at the top.

  • DOM. Shows objects that are markup (DOM) elements and their retained size. By default, these are sorted by retained size.

  • WinRT. Shows Windows managed and unmanaged objects that are referenced from your JavaScript app. By default, these are sorted by retained size.

Most of the views, such as the Dominators view, show similar value types. These values include:

  • Identifier(s). Name that best identifies the object. For example, for HTML elements we show the ID attribute value, if one is used.

  • Type. Type name of the object.

  • Size. Size of the object, not including the size of any referenced objects.

  • Retained Size. Sum of the object size plus the size of all child objects that have no other parent objects. For practical purposes, this sum is the amount of memory retained by the object, so if you delete the object you reclaim the specified amount of memory.

  • Count. The number of instances of the object. This value appears only in the Types view.

In the JavaScript Memory Analyzer, you can compare a snapshot against a previous snapshot in a snapshot diff view.

In the summary view, you can view the differential snapshot details by clicking another snapshot in the drop-down list in the upper-right corner of a snapshot summary tile.

The snapshot diff enables you to view differential information about dominators, types, roots, DOM objects, and Windows Runtime objects.

The snapshot diff shows any objects that were added to the heap between the two snapshots. In the differential Roots view (and the Reference Graph), a light gray text color indicates that the object itself existed in the previous snapshot, but that it has a child that didn’t.

This illustration shows the Dominators view in a snapshot diff.

Snapshot differential in Dominators view

In the snapshot diff views, views like the Dominators view are the same as in the snapshot details view. The snapshot diff views show the same value types as the snapshot details views, with these additional values:

  • Size Diff. Difference between the size of the object in the current snapshot and its size in the comparison snapshot (the older snapshot), not including the size of any referenced objects.

  • Retained Size Diff. Difference between the retained size of the object in the current snapshot and its retained size in the comparison snapshot (the older snapshot). The retained size includes the object size plus the size of all child objects that have no other parent objects. For practical purposes, the retained size is the amount of memory retained by the object, so if you delete the object you reclaim the specified amount of memory.

  • Count Diff. Difference between the number of instances of the object in the current snapshot and the number of instances in the comparison snapshot. This value appears only in the Types view.

In the Dominators, Types, DOM, and WinRT views, you can see the relationship of a particular object to the Global object. By using this feature, you can easily find a known object in the Roots view without searching through the Global object tree.

To use the feature, right-click an identifier in the Dominators, Type, DOM, or WinRT view, and click Show in roots view.

In the Dominators, Types, DOM, and WinRT views, you can filter out data by searching for particular identifiers. To search for an identifier, just type the value in the Identifier filter text box. When you begin typing characters, identifiers that don't contain the typed characters are filtered out.

Each view has its own filter, so the filtered info is not carried over among views.

The lower panes of the Dominators, Types, DOM, and WinRT views contain a Reference Graph that you can use to view shared references. If you select an object in the upper pane, the Reference Graph displays a list of references that point to the selected object.

If you want general help to identify equivalent objects, you can do this in the upper pane by clicking Display object IDs in the settings drop-down list in the upper-right corner of the pane. When you click this option, the object IDs appear next to the objects in the Identifier(s) list. Objects with the same ID are shared references.

In the Dominators, Types, DOM, and WinRT views, you can display built-in objects. By default, these views show only the objects that you create in your app. This helps to filter out unneeded information and isolate app-related issues. But at times it might be useful to view all objects that are generated for your app by the JavaScript runtime. You can view these objects in the JavaScript Memory Analyzer.

To display these objects, click Show built-ins in the settings drop-down list in the upper-right corner of the pane.

Diagnostic snapshot summaries, along with the associated details views, are saved as .diagsession files. Solution Explorer displays previous diagnostics sessions in the Diagnostic Sessions folder. In Solution Explorer, you can open previous sessions or remove or rename files.

The JavaScript Memory Analyzer supports the following two JavaScript Console commands that you can use in your code to help isolate the section of code where a memory issue is occurring. These commands throw an exception if you add them to the app and run the app in any context other than the memory analyzer (Though you can test whether the commands exist before using them. The commands will not exist early in the session startup phase.)

  • console.takeHeapSnapshot takes a heap snapshot that appears in the JavaScript Memory Analyzer.

  • console.profileMark sets a profile mark (the User Mark triangle) that appears in the timeline of the memory graph in the summary view. This command takes one string argument that represents a description of the event, and appears as a tooltip in the memory graph. This description must not exceed 100 characters.

The following code example shows how you can safely call takeHeapSnapshot.

    if (console && console.takeHeapSnapshot) {
        console.takeHeapSnapshot();
    }

The following code example shows how you can safely call profileMark.

    if (console && console.profileMark) {
        console.profileMark("Initialized");
    }

These tips might help you diagnose memory usage issues:

  • Use the Dominators view of a snapshot diff to try to identify major memory issues quickly.

  • Use the Show in roots view to help identify where an object is referenced in the overall memory hierarchy.

  • When the cause of a memory issue is difficult to identify, use the various views (such as Dominators and Types) to look for commonalities, like related objects and types.

  • Consider whether it would help to temporarily modify code to isolate problems. For example, you might want to:

    • Use the JavaScript Console Commands for the memory analyzer, console.takeSnapshot and console.profileMark.

      You can use these commands to isolate issues that you can’t isolate by manually clicking Take Heap Snapshot.

    • Create a test object that can be found easily in the JavaScript Memory Analyzer views, such as the Dominators view. For example, you can attach a very large object to another object to see whether a particular object or element has been garbage collected.

  • Look for objects that are retained in memory inadvertently after navigation to a new page has occurred, which is a common cause of memory issues. For example, the incorrect use of the URL.CreateObjectUrl function can result in this problem.

Show: