Debugging Memory Leaks on Android (for Beginners)
来源:互联网 发布:window.open php 编辑:程序博客网 时间:2024/05/16 19:22
使用Debug.dumpHprofData 分析内存泄漏
原文链接:https://www.novoda.com/blog/debugging-memory-leaks-on-android-for-beginners-programmatic-heap-dumping-part-1/
This is the first post in a series about debugging Android memory issues—subsequent posts will deal with using Eclipse Memory Analyzer to inspect heap dumps, as well as looking at common Android-specific memory consumption pitfalls. We’ll start with Programmatic Heap Dumping.
The contents of this post ought to be useful to developers new to the Android platform (regardless of Java experience) as it details Android-specific APIs and the use of Android SDK utilities to successfully interoperate with the standard JVM toolchain (e.g. hprof-conv which converts Dalvik heap dumps into the J2SE HPROF format, expected by Eclipse Memory Analyzer; MAT). Once this has been accomplished, the process of debugging leaks is more or less identical for Android applications and standard Java code running on a traditional JVM.
What’s a Heap?
All we really need to know about the heap for the purposes of this post is that it’s a slab of VM-managed memory into which (most) Java objects are allocated—certainly all of the objects we’re likely to care about. When we’re talking about the heap size of a particular object—how much of the heap it occupies—we talk of Shallow Size (or Shallow Heap) and Retained Size (or Retained Heap). The shallow size is the amount required for an object itself, while the retained size is the amount required for an object and all of the objects it refers to (i.e. via instance attributes).
A heap dump is a portable (i.e. file-based) representation of a VM’s heap at a particular point in time.
Obtaining Heap Dumps On Demand
Interactively getting an Android process to dump its heap is trivial with DDMS (there’s a Dump HPROF File button). That’s not our concern; we’re focused on obtaining dumps at particular points in a program’s execution by using the android.os.Debug API, which is an approach we might want to take if pathological memory consumption is peaking at points which aren’t easily identified through interactive use.
That said, our example is fairly contrived—an in-app Button which triggers a heap dump is isomorphic to the Dump HPROF File DDMS feature—figuring out when to trigger the dumping is entirely application-specific—the code samples are to illustrate how to do it, using a triggering mechanism likely to be familiar to anybody who’s written an interactive Android application.
Here’s an example of a View.OnClickListener which accepts a String data directory, and writes a heap dump within it, when the onClick method is invoked:
package com.novoda.example.MemoryLeaker;
import android.os.Debug;
import android.view.View;
import java.io.File;
import java.io.IOException;
public class HeapDumpOnClickListener implements View.OnClickListener {
private static final String HPROF_DUMP_BASENAME = “MemoryLeaker.dalvik-hprof”;
private final String dataDir;
public HeapDumpOnClickListener(String dataDir) { this.dataDir = dataDir;}@Overridepublic void onClick(View v) { String absPath = new File(dataDir, HPROF_DUMP_BASENAME).getAbsolutePath(); try { // this'll cause a collection Debug.dumpHprofData(absPath); } catch (IOException e) { e.printStackTrace(); }}
}
view rawHeapDumpOnClickListener.java hosted with ❤ by GitHub
Below is an excerpt of an Activity which attaches the above listener to a Button, and passes in a sensible value for the path prefix, so that the dump ends up somewhere useful (note that this method will overwrite an existing file at the supplied path):
package com.novoda.example.MemoryLeaker;
import android.app.Activity;
import android.os.Bundle;
public class LeakingActivity extends Activity {
…
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
findViewById(R.id.btn_heap).setOnClickListener( new HeapDumpOnClickListener(getApplicationInfo().dataDir));}...
}
view rawLeakingActivity.java hosted with ❤ by GitHub
When the Dump Heap button is activated, we’ll be able to retrieve the file from the Android device/emulator by executing the following command on the host machine (assuming
% adb pull /data/data/com.novoda.example.MemoryLeaker/MemoryLeaker.dalvik-hprof
226 KB/s (9160365 bytes in 17.973s)
If we plan to do anything with the heap dump, we’ll need to convert it to the J2SE format, as outlined above, using the hprof-conv binary, in
% hprof-conv MemoryLeaker.dalvik-hprof MemoryLeaker.hprof
% ls -lh MemoryLeaker.hprof
-rw-r–r– 1 moe staff 9.2M 18 Apr 15:33 MemoryLeaker.hprof
Grabbing a Heap Dump When Things Go Wrong
Alternatively, if we’re dealing with a worst-case scenario and have absolutely no idea what’s causing the leakage, or lack the patience to babysit the application until it falls apart, we can install a handler which’ll catch an OutOfMemoryError and try to write a snapshot of heap use at that point. Alternatives would be using either Activity.onLowMemory or Application.onLowMemory, which have vaguely defined semantics, and are not as definitively catastrophic as an uncaught OOM (from Application’s documentation: “this is called when the overall system is running low on memory, and would like actively running process to try to tighten their belt. While the exact point at which this will be called is not defined…”).
Back to Uncaught exception handlers: these are per-Thread, which is clear from the entrypoint—Thread’s setUncaughtExceptionHandler instance method. Below is an example of a Thread.UncaughtExceptionHandler suitable for passing in:
package com.novoda.example.MemoryLeaker;
import android.os.Debug;
import java.io.File;
import java.io.IOException;
public class HeapDumpingUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
private static final String HPROF_DUMP_BASENAME = “LeakingApp.dalvik-hprof”;
private final String dataDir;
public HeapDumpingUncaughtExceptionHandler(String dataDir) { this.dataDir = dataDir;}@Overridepublic void uncaughtException(Thread thread, Throwable ex) { String absPath = new File(dataDir, HPROF_DUMP_BASENAME).getAbsolutePath(); if(ex.getClass().equals(OutOfMemoryError.class)) { try { Debug.dumpHprofData(absPath); } catch (IOException e) { e.printStackTrace(); } } ex.printStackTrace();}
}
view rawHeapDumpingUncaughtExceptionHandler.java hosted with ❤ by GitHub
And the code to set this up at Application startup:
package com.novoda.example.MemoryLeaker;
import android.app.Application;
public class MemoryLeakingApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
Thread.currentThread().setUncaughtExceptionHandler( new HeapDumpingUncaughtExceptionHandler(getApplicationInfo().dataDir));}
}
view rawMemoryLeakingApplication.java hosted with ❤ by GitHub
Next Steps
The next post in this series will detail how to use MAT to find likely culprits in a heap dump which has been fetched and converted using the above method.
- Debugging Memory Leaks on Android (for Beginners)
- Avoid memory leaks on Android
- Debugging Memory on Linux
- On Memory Leaks in Java and in Android.
- [转载]On RArray AppendL() memory leaks
- finding memory leaks for Solaris applications
- Remote Debugging on Android
- Debugging Chromium on Android
- Debugging Deadlocks on Android
- Debugging RxJava on Android
- Tips for debugging on Linux
- Android articles 翻译之一:Avoiding Memory Leaks
- HUNTING YOUR LEAKS: MEMORY MANAGEMENT IN ANDROID
- Windows CE Virtual Memory Layout for Debugging
- Windows CE Virtual Memory Layout for Debugging
- Chrome Remote Debugging on Android
- Remote Debugging Chrome on Android
- Remote Debugging Chrome on Android
- 图像情感识别
- 垃圾收集器
- 字符变量和字符指针的正确使用
- 第十三周上机实践项目:阅读、修改和运行关于交通工具类的程序(2)
- STL源码剖析——内存管理
- Debugging Memory Leaks on Android (for Beginners)
- FrameLayout
- 动作栏和选项菜单
- 欢迎使用CSDN-markdown编辑器
- Serializable接口
- LeetCode Reorder List
- LINE分享android利用系统自带分享实现LINE分享功能
- java中int和Integer的区别
- 异常处理编程