Android OOM Analysis and the Shooter Offline Memory Profiling Tool
The article explains common Android Out‑Of‑Memory scenarios, traditional analysis methods, and introduces the Shooter offline memory analysis system that parses hprof snapshots, builds dominator trees, computes shallow and retained sizes, and visualizes reference chains to help developers locate memory leaks and OOM causes.
In daily development, crashes are often diagnosed via stack traces, but memory leaks and Out‑Of‑Memory (OOM) issues cannot be pinpointed from stacks; they require analyzing memory dumps, which traditionally needs expert knowledge. To address this, a dedicated offline memory analysis system called Shooter was developed.
Android applications receive a device‑specific memory quota. When the app repeatedly allocates memory and approaches this limit, a request larger than the remaining space triggers an OOM crash. The article lists four typical OOM causes: insufficient or fragmented heap space, exceeding the maximum number of file descriptors (FD), exceeding the maximum thread count, and exhausting virtual memory.
Common analysis approaches include integrating LeakCanary during development, capturing heap snapshots via Debug.dumpHprofData(String fileName) and analyzing them with the Eclipse Memory Analyzer (MAT), and using command‑line tools to obtain memory dumps.
The Shooter tool automates offline analysis of hprof files. Developers upload the snapshot, and the tool parses the file, constructs a dominator tree, calculates RetainSize, and builds reference chains to present memory usage results.
Parsing the hprof file extracts heap information such as class data, stack frames, and object instances. Android uses several heap types: Default Heap (unspecified), App Heap (allocation space for the app), Image Heap (system image classes), and Zygote Heap (shared process heap). The analysis treats GC Roots as entry points for reference graphs.
GC Roots include stack locals, live threads, JNI locals/globals, and cross‑generation references. They are dynamic; a root in one snapshot may not be a root in another.
The dominator tree is built by identifying, for each node, the nearest dominating node (the node that must be traversed to reach it). Shallow Size is the memory occupied by an object itself, while Retained Size is the sum of Shallow Sizes of all objects dominated by it. The article outlines an iterative algorithm using topological order and LCA (lowest common ancestor) queries, noting that cycles break topological ordering and require repeated passes or the Lengauer‑Tarjan algorithm.
Retained Size is computed by propagating each node’s Shallow Size up the dominator tree. Special handling is required for objects like Bitmap.mBuffer that become GC Roots, ensuring their size contributes to the owning Bitmap’s retained size.
After identifying suspicious objects via large Retained Sizes, the tool constructs reference chains using a breadth‑first search from the object to GC Roots, recording the shortest paths. This yields a tree of references that can be visualized.
The analysis focuses on several dimensions: Activity/Fragment instance leaks, image memory consumption (highlighting large bitmaps), and generic object reference chains. Visualizations show the number of instances and memory occupied by each object type, helping developers locate the root cause of OOM.
In conclusion, Shooter provides offline memory monitoring for Android apps, complementing other performance metrics such as network, WebView, and image monitoring. Although current limitations include GC pauses during dump and large hprof memory footprints, ongoing work aims to improve stability and coverage.
JD Retail Technology
Official platform of JD Retail Technology, delivering insightful R&D news and a deep look into the lives and work of technologists.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.