CN

Android Memory Optimization (2) - Advanced MAT Usage

Word count: 1.5kReading time: 9 min
2015/04/11
loading

This is the second article in our MAT series, focusing on advanced techniques for analyzing memory issues in Java and Android applications.

  1. Android Memory Optimization (1) - Introduction to MAT
  2. Android Memory Optimization (2) - Advanced MAT Usage
  3. Android Memory Optimization (3) - Viewing Original Bitmaps in MAT

Technical review — 2026-10-13: The 2015 screenshots are retained; concepts and query descriptions were checked against MAT 1.17.0 documentation. The old Studio conversion/GC menus are historical. Reference directions, unreachable-object interpretation, and leak criteria are corrected below, with missing steps restored.

For capture, see the introductory article: obtain a heap dump in Android Studio Profiler with debuggable / complete data, then export to MAT as needed. LeakCanary can support automated tests, but the ordinary leakcanary-android dependency belongs in debug builds. The official 2.14 release-analysis workflow is still marked experimental; adding LeakCanary is not a generic production-capture strategy. See UI-test integration and LeakCanary for releases.

Characteristics of Java Memory Leaks

  • A typical Java memory leak is an object that is still reachable but no longer useful.
  • Compare its intended lifetime with the actual ownership path, rather than judging only its size or instance count.
  • Recreating reusable objects adds allocation and GC work. If old objects are collected normally, that is allocation waste, not necessarily a leak. An oversized legitimate allocation can also cause OOM.

Advanced MAT Techniques

Dumping Memory with Android Studio

The screenshot shows an early Android Studio capture UI:

Historical Android Studio heap tools

Use the current heap-dump workflow: select Analyze Memory Usage (Heap Dump), inspect instances and references, then export .hprof from Past Recordings. Debug.dumpHprofData() can capture at a chosen point in app code, but dumping introduces pauses and overhead; it is not cost-free continuous sampling.

Convert Android-format HPROF with hprof-conv when the destination analyzer requires it, keeping input and output filenames different. The historical right-click conversion command is not a menu guaranteed in every Studio version.

Manual GC is neither mandatory nor a guarantee. Runtime.gc() requests a best-effort collection; it does not promise a snapshot with no unreachable objects afterward. Comparable post-GC snapshots can help examine lasting retention. For short-lived allocation churn, collecting first can remove useful evidence. The old button is shown below:

Historical Initiate GC button

Unreachable Objects

An object with no path from ordinary GC Roots in the parsed graph is considered unreachable. It may no longer be needed but not yet collected. Dump format, parsing options, and configured object discarding also affect this result, so it does not prove that no GC previously ran.

Unreachable Objects entry point

Unreachable Objects Histogram

By default, MAT removes these objects from its main parsed graph while retaining a summary of class names, counts, and shallow sizes. The Unreachable Objects Histogram has no complete per-object reference graph behind it. See the official explanation.

The old Calculate Retained Size menu distinguishes the quick lower-bound estimate, Minimum, from Precise calculation for an object set:

Calculate Retained Size

Retained Heap in the historical unreachable table

The zero Retained Heap values in this old summary table do not mean that the objects occupy no memory, or that every unreachable object must always have zero retained size. Parsing with the objects retained creates different analysis conditions.

To inspect their references, follow MAT’s reparse procedure:

  1. Close the snapshot.
  2. Use Heap Dump History → Delete Index Files for that snapshot, retaining the original HPROF.
  3. Enable Preferences → Memory Analyzer → Keep unreachable objects.
  4. Reopen the dump and let MAT reparse it.
  5. Run Java Basics → GC Roots, select Unreachable Objects, and run Show Retained Set.

MAT introduces special unreachable roots to keep those objects available for analysis. These are analyzer-created roots, not real strong-reference owners in the app.

Histogram Analysis

Histogram usually aggregates instance counts and shallow heap by class. It is a useful starting point for investigating large consumers or unexpected counts.

  • Sort by actual columns such as object count or Shallow Heap. A Percentage column in one view is not universal.
  • Group by class loader or package to narrow the investigation; Dominator Tree also offers grouping.
  • Repeat the same entry/exit scenario and capture comparable states. Growth may reflect cache warm-up, pending work, or a leak; inspect lifetimes and ownership paths.
  • Histogram shows classes and counts; Dominator Tree shows domination. A dominator-tree edge need not be an actual field reference. Use incoming/outgoing references for the object graph.

Histogram Group by Package

For a growing class, inspect concrete instances, determine which should have gone away, and find what retains them. Count growth alone does not prove a leak.

Histogram grouping

Thread Information

MAT shows thread information present in the snapshot. Stack and local-variable availability depends on the dump format and parser settings. See Thread Overview.

Thread Overview

The original screenshots suggest two lines of investigation:

  1. Threads retaining substantial heap. Inspect their tasks, local references, and context. Retained heap is not the thread’s total native-stack allocation.

    Heap retained through threads

  2. An unexpected thread count. Check names, pool sizing, and task completion. Many threads alone are not sufficient evidence of a leak.

    Thread count

Context Menus and Help

Right-click a result item to find analysis options:

Context Menu Options

Use Search Queries or Query Browser to find a command and read its description and arguments; its fixed position in an old menu is unimportant.

Query descriptions and arguments

These are MAT analysis queries, not necessarily configured SQL statements. MAT separately supports OQL, an SQL-like language for querying heap objects, classes, and fields.

Here are the options we use most often, with their meanings from the List Objects documentation:

  • List Objects → with incoming references: Objects that reference the selected object.
  • List Objects → with outgoing references: Objects referenced by the selected object.
  • Path to GC Roots → exclude all phantom/weak/soft etc. references: Apply the preset’s non-strong referent exclusions to find retaining root paths. A path establishes reachability; the object must also have outlived its usefulness to justify a leak diagnosis. It does not establish that OOM has occurred.
  • Other exclusion presets or custom exclusions: Inspect the actual fields/types excluded. Excluding weak/soft references alone does not remove every other non-strong path. See the query arguments.
  • Merge Shortest Paths to GC Roots: Merge shortest paths for one or more objects to expose shared owners. It does not enumerate all retaining paths; after removing a shortest path, other paths may remain. See Merge Shortest Paths.

Debugging Bitmaps

Bitmap memory depends on decoded pixel dimensions, configuration, and actual allocation, not just whether the screen is “2K.” A tightly packed 2560 × 1440 ARGB_8888 image needs 14,745,600 pixel bytes, about 14.06 MiB. Reused allocation capacity can also exceed the current image’s requirements. On API 19+, inspect getAllocationByteCount(). See the Bitmap API.

Exporting a Bitmap’s byte[] from MAT is a conditional historical technique: the snapshot must contain the pixels, and their layout must be understood. From Android 8.0 / API 26, pixels reside in the native heap, so not every Bitmap has a directly recoverable Java-heap array. The original process is retained in Viewing Original Bitmaps in MAT; check its version and data requirements before using it.

Debugging ArrayLists

For an ArrayList instance, List Objects → with outgoing references reveals its backing storage and fields:

ArrayList Internal Structure

Expanding the backing array exposes the internal storage, but reading it element by element is awkward. Its capacity can exceed the list’s logical element count, and field names or layout may change between runtimes. For recognized implementations, use Java Collections → Extract List Values:

Extract List Values command

The result presents the elements more directly:

Extract List Values Result

The query depends on MAT recognizing that collection layout; it does not automatically support every custom container. When extraction is unsupported, inspect the actual class and fields. See collection queries.

Big Drops In Dominator Tree

Open Query Browser / Search Queries, find Big Drops in Dominator Tree, and run it on the current snapshot. See the query description.

The query looks for substantial drops in retained size across dominator-tree levels. It helps find an owner retaining many objects and may also show large arrays. Accumulation Point is a candidate concentration of memory; Dominator identifies the associated dominator, not necessarily a direct Java-field owner.

Big Drops In Dominator Tree

Inspect candidate contents and capacity, then follow incoming references and paths to GC Roots to find their owners. Judge them against the intended lifecycle: a large cache may be deliberate, while a small retained object can still leak. Big Drops provides a starting point rather than an automatic diagnosis.

About Me && Blog

Below are personal introduction and related links. I hope to communicate more with everyone in the industry. If three people walk together, there must be one who can be my teacher!

  1. Blogger Personal Introduction: There are personal WeChat and WeChat group links inside.
  2. This Blog Content Navigation: A navigation of personal blog content.
  3. Excellent blog articles organized and collected by individuals - A must-know for Android efficiency optimization: Everyone is welcome to recommend themselves and recommend others (WeChat private chat is fine)
  4. Android Performance Optimization Knowledge Planet: The paid community stopped operating in 2026 and no longer accepts new members; this link preserves its history.

One person can go faster, a group of people can go further

WeChat Scan

CATALOG
  1. 1. Characteristics of Java Memory Leaks
  2. 2. Advanced MAT Techniques
    1. 2.1. Dumping Memory with Android Studio
    2. 2.2. Unreachable Objects
    3. 2.3. Histogram Analysis
    4. 2.4. Thread Information
    5. 2.5. Context Menus and Help
    6. 2.6. Debugging Bitmaps
    7. 2.7. Debugging ArrayLists
    8. 2.8. Big Drops In Dominator Tree
  3. 3. About Me && Blog