Sieve – Android Memory Analysis System: Background, Implementation, and Techniques
This article introduces the Sieve Android memory analysis system, explains why existing tools like LeakCanary and MAT fall short, describes how heap dump files are parsed, GC Roots identified, dominator trees generated, retained sizes calculated, and reference chains constructed to help developers locate memory leaks and OOM causes.
Memory problems such as leaks and unreasonable usage often lead to OOM (Out Of Memory) crashes, affecting both user experience and developer debugging.
Issues with existing tools: LeakCanary only reports objects that developers deem should not exist, lacking a generic reference chain; MAT is Java‑VM‑centric and not friendly to Android, especially for large Bitmap objects.
Solution – Sieve: An internal JD.com tool that accepts an Hprof heap dump, parses it, and generates an analysis report showing activity/fragment usage, Bitmap memory, object reference paths, and class statistics.
Heap dump parsing: The Hprof file contains class info, stack frames, and heap objects. Objects may also be marked as GC Roots (e.g., Stack Local, Thread, JNI Local/Global, generational references). Parsing extracts these details into a snapshot data structure.
Snapshot types: Default Heap, App Heap, Image Heap, Zygote Heap – each representing different memory regions in the ART VM.
Dominator tree generation: A dominator point A dominates B if every path from the source to B passes through A. The dominator tree is built by finding each node's immediate dominator, using topological order for DAGs and iteratively handling cycles (or using the Lengauer‑Tarjan algorithm).
Shallow Size vs. Retained Size: Shallow Size is the object's own memory; Retained Size is the sum of Shallow Sizes of all nodes it dominates, indicating how much memory would be reclaimed if the object were collected.
Example code snippet illustrating Shallow Size calculation:
public class TestA {
int a;
TestB b;
}Retained Size calculation: Traverse the dominator tree, adding each node's Shallow Size to all its ancestors. Special handling is required for objects like Bitmap.mBuffer that become GC Roots, ensuring their size is attributed to the original Bitmap hierarchy.
Reference chain construction: After identifying suspect objects via large Retained Size, a breadth‑first search from the object to GC Roots builds shortest reference paths, which are stored in an adjacency‑list tree structure.
Example of the adjacency‑list class used:
public final class PathsFromGCRootsTree {
private String description;
private ArrayList
inboundTrees;
}Practical challenges: Dumping Hprof near OOM can trigger GC pauses; the dump file may be hundreds of megabytes, causing the analysis process to OOM. Strategies like threshold‑based instance pruning help but can lose reference accuracy.
Overall, Sieve provides a comprehensive pipeline—from heap dump parsing, GC Root identification, dominator tree construction, retained size computation, to reference chain extraction—to help Android developers diagnose memory leaks and OOM issues.
JD Tech
Official JD technology sharing platform. All the cutting‑edge JD tech, innovative insights, and open‑source solutions you’re looking for, all in one place.
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.