This page provides an overview of the tools available for examining memory usage in chrome.
No single tool can give a full view of memory usage in Chrome. There are too many different context involved (JS heap, DOM objects, native allocations, GPU, etc) that any tool that collected all that information likely would not be able to provide an actionable analysis.
Here is a table of common area of inquiry and suggested tools for examining them.
|Topic/Area of Inquiry
|Which subsystems consuming memory per process.
|Global Memory Dumps, Taking memory-infra trace
|Tracking C++ object allocation over time
diff_heap_profiler.py, Heap Details in chrome://tracing
|Suspected DOM leaks in the Renderer
|Developer Tools Heap Snapshots, Real World Leak Detector
|Kernel/Driver Memory and Resource Usage
|perfmon (win), ETW
|Blackbox examination of process memory
|Symbolized Heap Dump data
If that seems like a lot of tools and complexity, it is but there's a reason.
Many Chrome subsystems implement the
trace_event::MemoryDumpProvider interface to provide self-reported stats detailing their memory usage. The Global Memory Dump view provides a snapshot-oriented view of these subsystems that can be collected and viewed via the chrome://tracing infrastructure.
In the Analysis split screen, a single roll-up number is provided for each of these subsystems. This can give a quick feel for where memory is allocated. The cells can then be clicked to drill into a more detailed view of the subsystem's stats. The memory-infra docs have more detailed descriptions for each column.
To look a the delta between two dumps, control-click two different dark-purple M circles.
Global Memory Dump tab within the Analysis View in bottom split screen.
Clicking on the cell pulls up a view that lets you examine the stats collected by the given MemoryDumpProvider however that view is often way outside the viewport of the analysis view. Be sure to scroll down.
GUI method of exploring the heap dump for a process.
TODO(awong): Explain how to interpret + interact with the data. (e.g. threads, bottom-up vs top-down, etc)
Global Memory Dump tab of the Analysis View.
On step 5, the
Component Details and
Heap Dump views that let you examine the information collected by the given MemoryDumpProvider is often way outside the current viewport of the Analysis View. Be sure to scroll down!
Currently supported allocators: malloc, PartitionAlloc, Oilpan.
This is most useful for examining allocations that occur during an interval of time. This is often useful for finding leaks as one call-stack will rise to the top as the leak is repeated triggered.
Multiple traces can be given at once to show incremental changes. A similar analysis can be had via ctrl-clicking multiple Global Memory Dumps in the chrome://tracing UI but loading multiiple detailed heapdumps can often crash the chrome://tracing UI. This tool is more robust to large data sizes.
The source code can also be used as an example for manually processing heap dump data in python.
TODO(awong): Write about options to script and the flame graph.
diff_heap_profiler.py to show a list of new allocations.
Heap dumps provide extremely detailed data about object allocations and is useful for finding code locations that are generating a large number of live allocations. Data is tracked and recorded using the Out-of-process Heap Profiler (OOPHP).
For the Browser and GPU process, this often quickly finds objects that leak over time.
This is less useful in the Renderer process. Even though Oilpan and PartitionAlloc are hooked into the data collection, many of the stacks end up looking similar due to the nature of DOM node allocation.
VirtualAlloc()) will not be tracked.
enable_framepointers=true is required.
|Out of process heap profiling start mode.
|This option is somewhat misnamed. It tells OOPHP which processes to profile at startup. Other processes can selected manually later via chrome://memory-internals even if this is set to “disabled”.
|Keep track of even the small allocations in memlog heap dumps.
|By default, small allocations are not emitted in the heap dump to reduce dump size. Enabling this track all allocations.
|The type of stack to record for memlog heap dumps
|If possible, use Native stack frames as that provides the best information. When those are not available either due to performance for build (eg, no frame-pointers on arm32 official) configurations, using trace events for a “pseudo stack” can give good information too.
|Deprecated. Enables the in-process heap profiler. Functionality should be fully subsumed by preceeding options.
symbolize_trace.py. If the Chrome binary was built locally, pass the flag “--is-local-build”.
diff_heap_profiler.py, or Heap Profile view in Chrome Tracing
On desktop, using chrome://memory-internals to take a heap dump is more reliable as it directly saves the heapdump to a file instead of passing the serialized data through the chrome://tracing renderer process which can easily OOM. For Android, this native file saving was harder to implement and would still leave the problem of getting the dump off the phone so memory-infra tracing is the current recommended path.
Examining self-reported statistics from various subsystems on memory usages. This is most useful for getting a high-level understanding of how memory is distributed between the different heaps and subsystems in chrome.
It also provides a way to view heap dump allocation information collected per process through a progressively expanding stack trace.
Though chrome://tracing itself is a timeline based plot, this data is snapshot oriented. Thus the standard chrome://tracing plotting tools do not provide a good means for measuring changes per snapshot.
This should produce a view of the trace file with periodic “light” and “heavy” memory dumps. These dumps are created periodically so the time spent waiting in step (3) determines how many dumps (which are snapshots) are taken.
Warning: If OOPHP is enabled, the tracing UI may not be able to handle deserializing or rendering the memory dump. In this situation, save the heap dump directly in chrome://memory-internals and use alternate tools to analyze it.
TODO(ajwong): Add screenshot or at least reference the more detailed memory-infra docs.
Heap snapshots provide views of objects on the Oilpan and V8 heaps and retainer relationships between them. General documentation is here: https://developer.chrome.com/docs/devtools/memory-problems/heap-snapshots/
By default, many objects on the Oilpan heap will be labeled as “InternalNode”. To capture detailed symbol names for them, follow these steps:
Add the following to gn args and rebuild:
cppgc_enable_object_names = true
Or use Chrome for Testing prebuilt binaries; they have this flag enabled.
In Developer Tools, under Settings | Experiments, check “Show option to expose internals in heap snapshots”
Reload Developer Tools (there will be a button for this at the top of the window)
On the Memory pane, under Select profiling type | Heap snapshot, check “Expose internals (includes additional implementation-specific details)”
TODO(awong): Fill in.
Each OS provides specialized tools that give the closest to complete information about resource usage. This is a list of commonly interesting tools per platform. Use them as search terms to look up new ways to analyze data.
|SysInternals vmmap, resmon (can track kernel resources like Paged Pool), perfmon, ETW, !heap in WinDbg
There is a natural tradeoff between getting detailed information and getting reliably complete information. Getting detailed information requires instrumentation which adds complexity and selection bias to the measurement. This reduces the reliability and completeness of the metric as code shifts over time.
While it might be possible to instrument a specific Chrome heap (eg, PartitionAlloc or Oilpan, or even shimming malloc()) to gather detailed actionable data, this implicitly means the instrumentation code is making assumptions about what process resources are used which may not be complete or correct.
As an example of missed coverage, none of these collection methods can notice kernel resources that are allocated (eg, GPU memory, or drive memory such as the Windows Paged and Non-paged pools) as side effects of user mode calls nor do they account for memory that does not go through new/malloc (manulaly callling
VirtualAlloc()). Querying a full view of these allocations usually requires admin privileges, the semantics change per platform, and the performance can vary from being “constant-ish” to being dependent on virtual space size (eg, probing allocation via VirtualQueryEx or parsing /proc/self/maps) or number of processes in the system (NTQuerySystemInformation).
As an example of error in measurement, PartitionAlloc did not account for the Windows Committed Memory model bug leading to a “commit leak” in Windows that was undetected in its self-reported stats.
Relying on a single metric or single tool will thus either selection bias the data being read or not give enough detail to quickly act on problems.