| # Memscope and Memory Overview | |
| NOTE: Memscope and Memory Overview are currently under heavy development, so | |
| while they are now available on all branches, you may get better results using | |
| the **canary** or **autopush** channel. Change the channel using the | |
| [release channel flag](https://ui.perfetto.dev/#!/flags/releaseChannel). | |
| Perfetto provides two complementary features for memory analysis: | |
| - **Memscope** - A live memory monitor showing system-level and per-process | |
| stats from a running device. Provides shortcuts to start tracing a specific | |
| process. | |
| - **Memory Overview** - Appears after recording a trace, providing a high-level | |
| overview of the memory information, blending smaps snapshots, ART heap dumps | |
| and native profiling, with links to drill down further using | |
| [Heap Dump Explorer](/docs/visualization/heap-dump-explorer.md) and the | |
| existing memory tracks on the timeline. | |
| This guide walks through recording a trace with Memscope and analyzing it in the | |
| Memory Overview page. | |
| NOTE: Recording smaps snapshots requires Android build `ZP1A.260626.001` or | |
| newer. | |
| ## Memscope: Live Memory Profiling | |
| Memscope lets you connect to an Android device or Linux host and watch system | |
| and per-process memory metrics update in real time. It is useful for: | |
| - Checking the overall health of the system (memory pressure / thrashing / | |
| LMKs). | |
| - Finding which processes are growing over time. | |
| - Spot-checking memory usage before and after a specific action. | |
| - Starting a trace for a specific process. | |
| ### Starting a live Memscope session | |
| 1. Open https://ui.perfetto.dev and click **Memscope** in the sidebar. | |
|  | |
| 2. Connect to your device or host using one of the available transports. The | |
| recording options are identical to those on the record page. If you are | |
| unsure which to pick, WebUSB is the easiest option for Android devices | |
| connected via USB. | |
| 3. Once connected, Memscope displays a dashboard of system stats and a | |
| task-manager-style list of running processes and their memory stats. The | |
| dashboard updates every few seconds. | |
|  | |
|  | |
| You can click through the tabs at the top of the page to see various | |
| system-level memory stats such as page cache usage and memory pressure. | |
| ### Process monitoring | |
| Use the process table to: | |
| - **Sort by memory usage** - by default the process list is sorted by descending | |
| RSS Anon + Swap usage. | |
| - **Watch trends** - the sparkline next to each process shows recent RSS | |
| direction - processes with consistently upward trends are good candidates for | |
| deeper investigation. | |
| - **Search for a process** - use the filter box to search for a specific process | |
| or package by name. | |
| - **Profile a process** - hover over a process row to reveal the **Profile** | |
| button - click it to start a heap profile for that process. | |
|  | |
| In this example, we are going to test a dummy app that intentionally leaks | |
| native memory. | |
| ### Recording and opening a trace | |
| After clicking **Profile**, Memscope starts recording the selected process using | |
| a pre-configured memory trace configuration. | |
| This pre-configured trace config includes: | |
| - Periodic [Java (ART) heap dumps](/docs/data-sources/java-heap-profiler.md) | |
| (every 10s). | |
| - Periodic smaps dumps (every 10s). | |
| - [Native heap profiling](/docs/data-sources/native-heap-profiler.md) (dumped | |
| every 5s). | |
| Exercise the app or otherwise reproduce the behavior you want to investigate, | |
| then click **Stop & Open Trace**. You can monitor the high-level memory usage | |
| using the stacked area graph on this page. | |
|  | |
| ## Memory Overview: Post-Hoc Memory Triage | |
| The Memory Overview page opens by default for any trace that contains smaps | |
| snapshots, but you can also find it in the sidebar under **Memory Overview**. It | |
| provides a comprehensive view of memory usage for a given process over the | |
| duration of the trace. | |
| NOTE: For Googlers, you can find good examples of traces with smaps dumps via | |
| the | |
| [process_smaps dashboard](https://apconsole.corp.google.com/dashboards/process_smaps). | |
| However, these usually contain only a single dump, so the timeline view on this | |
| page will be hidden. | |
| ### Process selector and headline stats | |
| At the top of the page, the process selector lets you pick which process to | |
| inspect. By default, the process with the highest number of memory-relevant | |
| stats is selected. If you have recorded a trace via Memscope, this process will | |
| be selected automatically, as it only records a single process. | |
|  | |
| ### Composition chart | |
| The composition-over-time chart shows how memory is broken down by category | |
| (anon, file, shmem, etc.) based on the information in the smaps snapshots. This | |
| is used for top-level temporal navigation for the rest of the page. You can: | |
| - **Select single snapshots** - click points on the chart to inspect specific | |
| snapshots. The following sections show a breakdown of this snapshot only. | |
| - **Drag across a range** - click and drag across multiple snapshots to compare | |
| snapshots and see how memory use has changed over time. | |
|  | |
| In this example, we can see that native memory started increasing rapidly | |
| towards the end of the trace (after we started interacting with the app). | |
| #### Where the growth went | |
| This bar shows a breakdown of how the memory growth within the selected region | |
| is split into the various high-level categories. If a single snapshot is | |
| selected, it shows the delta from the start of the trace. | |
| ### Memory breakdown sections | |
| Below the chart, Memory Overview provides several sections for drilling into | |
| memory usage. | |
| #### Where did all the memory go? | |
| This section provides a breakdown of resident memory based on smaps data for the | |
| selected snapshot (absolute, not delta). Use it to determine which sections | |
| below are consuming the most memory. | |
|  | |
| In this example, we can see that native memory is using a large proportion. | |
| #### Java heap | |
| For ART processes, the Java section explains heap usage and lists the heaviest | |
| retained objects by various metrics, grouped by class name. Clicking any of the | |
| class names reveals the contributing objects in Heap Dump Explorer. | |
|  | |
| #### Bitmaps | |
| The bitmap section summarizes the largest and most frequent bitmaps grouped by | |
| dimension. | |
|  | |
| #### Native allocations | |
| The native allocation section shows the top unreleased memory allocation call | |
| sites (allocations for which we haven't seen a subsequent free). Note that it | |
| cannot account for all native memory usage - only for allocations made since we | |
| started recording the trace. In our example it covers 87%, so we can get a good | |
| idea of where the memory is going. | |
|  | |
| We can see that a native function in the mandelbrot engine has allocated 182 MB | |
| without freeing it. This function originates from a native tile rendering | |
| library in the dummy app used to generate the mandelbrot bitmaps and send them | |
| back to the Java runtime for composition. It should not retain much, if any, | |
| memory. The intentional leak was, in fact, caused by skipping the call to free | |
| the image buffer for rendered tiles, so every call into the native code would | |
| leak one 512x512px buffer, which has added up steadily over time. | |
| Click on the 'Show in timeline' button to drill down into the native allocation | |
| flamegraph in more detail. | |
| #### Smaps Detail | |
| Scrolling back up to the top of the page, click the **Smaps Detail** tab at the | |
| top of Memory Overview to inspect the raw `/proc/<pid>/smaps` data. The table | |
| groups mappings using the same categories as the composition chart. | |
|  | |
| ## Putting it together: A workflow | |
| In summary, a typical memory investigation workflow looks like this: | |
| 1. **Find the process** - use Memscope to monitor memory live and identify which | |
| process is growing or find the process you're looking to monitor. | |
| 2. **Start tracing the process** - click to start profiling the offending | |
| process, then open the trace in the UI. | |
| 3. **Triage in Memory Overview** - open the trace and use the composition chart | |
| and breakdown sections to understand where the memory went. | |
| 4. **Go deeper** - if needed, start a native heap profile from Memscope or | |
| record a new trace with heap profiling enabled to get allocation call stacks. | |
| ## See also | |
| - [Memory Profiling guide](/docs/getting-started/memory-profiling.md) - overview | |
| of native heap profiling, ART heap dumps, and allocation profiling. | |
| - [Memory counters](/docs/data-sources/memory-counters.md) - per-process memory | |
| counters and events from the kernel. | |
| - [Native heap profiler](/docs/data-sources/native-heap-profiler.md) - deep dive | |
| into heapprofd allocation profiling. | |
| - [Heap Dump Explorer](/docs/visualization/heap-dump-explorer.md) - analyzing | |
| ART heap dumps object by object. | |
| - [Memory usage case study](/docs/case-studies/memory.md) - end-to-end guide to | |
| debugging memory issues on Android. |