Middle+
How to identify memory leaks when analyzing a dump?
sobes.tech AI
Answer from AI
Tools that analyze object graphs in the heap are used to identify memory leaks in a dump (HPROF file). Main steps:
-
Obtaining a memory dump:
- Using Android Studio Memory Profiler.
- Using the command
adb shell dumpheap <package_name> /data/local/tmp/dump.hprof. - Using the system call
Debug.dumpHprofData(filePath).
-
Analyzing the dump:
- Opening the dump in Android Studio: In Memory Profiler or via the "File" -> "Open" menu.
- Object analysis: Sorting objects by size (Shallow Size, Retained Size) and number of instances.
- Searching for suspicious objects: Look for classes that should be destroyed (e.g., Activity, Fragment, Contexts) but have a large number of instances or significant
Retained Size. - Studying the reference chain: Select a suspicious object and trace its path to root objects (GC roots). This shows who holds the reference, preventing garbage collection.
- Searching for static references: Static fields often cause leaks if they hold long-lived references to contexts or Views.
- Using LeakCanary: The library automates leak detection, dumping, and analysis at runtime, providing a detailed leak path description.
-
Interpreting the results:
- A long path to a GC root containing references to objects that should be destroyed indicates a problem.
- References from static fields, AsyncTask, Handlers with delays, improperly unregistered listeners/callbacks, or singletons in activities or views are often leak causes.
Example of analyzing a GC root path in Android Studio Memory Profiler:
// Example of a GC root path indicating a leak
// android.app.Activity instance with mDestroyed=true
// references android.widget.LinearLayout instance
// references android.view.View $ListenerInfo instance
// references com.example.MyActivity$1 instance (Anonymous class implementing View.OnClickListener)
// references com.example.MyActivity instance (Leaking this reference)
In this example, an anonymous class (button click listener) holds an implicit reference to MyActivity, even though the activity should be destroyed (mDestroyed=true). This listener is likely registered somewhere or held by another long-lived object (e.g., static field or singleton).