OOM(OutOfMemoryError) 相信是所有 Android 开发者遇到的最多的 Error,因此找出个中缘由是非常重要。

这里用到的分析工具主要是 Eclipse MAT 插件http://www.eclipse.org/mat/

Eclipse MAT(Memory Analyzer Tool)主要用于分析Java程序OOM 时 JVM 的 Heap dump文件(HPROF格式的二进制文件)。

一般的,Java 程序要生成这样的dump文件,需设置 JVM 启动参数-XX:-HeapDumpOnOutOfMemoryError(同样适用于Android应用)。

Android应用生成 dump 文件可以使用 DDMS,点击Devices工具”Dump HPROF file”,按提示框保存文件即可(如果安装了 MAT则会自动打开文件)。

具体就不再赘述…
相关阅读:

这里简单介绍一下用 MAT分析 Android 应用的内存泄露。

  1. 首先安装 MAT
    http://www.eclipse.org/mat/downloads.php下载或者用Update Sitehttp://download.eclipse.org/mat/1.4/update-site/安装
  2. 在 DDMS 中选择需要调试的设备及你的应用进程
  3. 点击“Dump HPROF file”按钮提取 dump 文件(需稍许等待)
  4. 自动用MAT 打开文件,选择“Leak Suspects Report”
  5. 睁大你的双眼揪出最有可能导致 OOM 的因素吧!

测试代码:

MainActivity.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package net.yrom.mat;

// imports...

public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}

SparseArray<Bitmap> bitmaps = new SparseArray<Bitmap>();
Random random = new Random();
public void rock(View v){
try {
for(int i=0;i<Integer.MAX_VALUE;i++){
bitmaps.append(i, Bitmap.createBitmap(random.nextInt(100)+1, random.nextInt(100)+1, Bitmap.Config.ARGB_8888));
}
} catch (OutOfMemoryError e) {
Log.e("@@@", "Got OOM!!!");
}
}
}

布局中只有一个按钮,点击后即执行rock(view)

手机开始疯狂的GC,几秒后即OOM

... ...
08-29 23:15:28.625: D/dalvikvm(1016): WAIT_FOR_CONCURRENT_GC blocked 255ms
08-29 23:15:28.625: I/dalvikvm-heap(1016): Forcing collection of SoftReferences for 3576-byte allocation
08-29 23:15:28.705: I/dalvikvm-heap(1016): Clamp target GC heap from 199.988MB to 192.000MB
08-29 23:15:28.705: D/dalvikvm(1016): GC_BEFORE_OOM freed 9K, 1% free 196404K/196608K, paused 79ms, total 79ms
08-29 23:15:28.770: I/dalvikvm-heap(1016): Clamp target GC heap from 199.991MB to 192.000MB
08-29 23:15:28.770: D/dalvikvm(1016): GC_FOR_ALLOC freed 0K, 1% free 196408K/196608K, paused 65ms, total 65ms
08-29 23:15:28.770: I/dalvikvm-heap(1016): Forcing collection of SoftReferences for 6836-byte allocation
08-29 23:15:28.845: I/dalvikvm-heap(1016): Clamp target GC heap from 199.991MB to 192.000MB
08-29 23:15:28.845: D/dalvikvm(1016): GC_BEFORE_OOM freed 0K, 1% free 196408K/196608K, paused 77ms, total 77ms
08-29 23:15:28.845: E/dalvikvm-heap(1016): Out of memory on a 6836-byte allocation.
08-29 23:15:28.845: I/dalvikvm(1016): "main" prio=5 tid=1 RUNNABLE
08-29 23:15:28.845: I/dalvikvm(1016):   | group="main" sCount=0 dsCount=0 obj=0x40c269a0 self=0x6cac5010
08-29 23:15:28.845: I/dalvikvm(1016):   | sysTid=1016 nice=0 sched=0/0 cgrp=apps handle=1074820060
08-29 23:15:28.845: I/dalvikvm(1016):   | state=R schedstat=( 0 0 0 ) utm=100 stm=73 core=3
08-29 23:15:28.845: I/dalvikvm(1016):   at android.graphics.Bitmap.nativeCreate(Native Method)
08-29 23:15:28.850: I/dalvikvm(1016):   at android.graphics.Bitmap.createBitmap(Bitmap.java:689)
08-29 23:15:28.850: I/dalvikvm(1016):   at android.graphics.Bitmap.createBitmap(Bitmap.java:666)
08-29 23:15:28.850: I/dalvikvm(1016):   at android.graphics.Bitmap.createBitmap(Bitmap.java:633)
08-29 23:15:28.850: I/dalvikvm(1016):   at net.yrom.mat.MainActivity.rock(MainActivity.java:25)
08-29 23:15:28.850: I/dalvikvm(1016):   at java.lang.reflect.Method.invokeNative(Native Method)
08-29 23:15:28.850: I/dalvikvm(1016):   at java.lang.reflect.Method.invoke(Method.java:511)
08-29 23:15:28.850: I/dalvikvm(1016):   at android.view.View$1.onClick(View.java:3593)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.view.View.performClick(View.java:4203)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.view.View$PerformClick.run(View.java:17556)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.os.Handler.handleCallback(Handler.java:725)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.os.Handler.dispatchMessage(Handler.java:92)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.os.Looper.loop(Looper.java:137)
08-29 23:15:28.855: I/dalvikvm(1016):   at android.app.ActivityThread.main(ActivityThread.java:5105)
08-29 23:15:28.855: I/dalvikvm(1016):   at java.lang.reflect.Method.invokeNative(Native Method)
08-29 23:15:28.855: I/dalvikvm(1016):   at java.lang.reflect.Method.invoke(Method.java:511)
08-29 23:15:28.855: I/dalvikvm(1016):   at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:793)
08-29 23:15:28.855: I/dalvikvm(1016):   at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:560)
08-29 23:15:28.855: I/dalvikvm(1016):   at dalvik.system.NativeStart.main(Native Method)
08-29 23:15:28.855: E/@@@(1016): Got OOM!!!
... ...

此时点击DDMS 上的“Dump HPROF file”

稍等片刻,MAT 自动打开

一览无遗