移动测试基础 [转] android OutOfMemory 时抓取 heap 快照

思寒_seveniruby · 2014年03月17日 · 1092 次阅读

这篇文章文章写的很不错,推荐大家读一下。

(这里不教你如何分析 heap 快照,只说明如何在关键时候抓取)
首先说一下,在程序没有崩溃的时候如何抓取 heap 快照。
这个大家应该都知道,在 ddms 中自带此功能。


见上图
首先我们选中一个进程,然后点击 Update Heap 按钮(小绿虫子旁边的按钮),这时就能看到 heap 使用情况
如果想取出快照详细分析,我们可以点击 Dump HPROF File 按钮,保存到电脑上面。使用 android-sdk/tools/hprof-conv 这个工具把文件转换一下,之后用 MAT 分析即可。
Java 代码 收藏代码
hprof-conv '/home/su1216/data.hprof' '/home/su1216/data_ok.hprof'

这时 MAT 能直接打开 data_ok.hprof 文件。

如果想要 OOM 时的内存快照该怎么办,我们总不能紧盯着手机的同时再盯着电脑,OOM 出现的瞬间抓取内存快照,这显然是不现实的。
如果 OOM 并不经常复现,那么我们会错过很多修改 bug 的机会,浪费很多时间。

下面给大家一种抓取 OOM 时的 heap 快照的方法
由于 OOM 时的 heap 快照较大,所以抓取的内存快照我选择保存到 sd 卡中,因此要有写入外部存储的权限
Xml 代码 收藏代码


然后我们需要实现 UncaughtExceptionHandler 这个接口
记得要设置未捕获异常的 Handler,设置为自己。
当出现了异常的时候,uncaughtException 方法会被调用,所以如果我们可以在这里抓取内存快照。
Java 代码 收藏代码

import java.lang.Thread.UncaughtExceptionHandler;  

import android.os.Debug;  
import android.os.Environment;  
import android.util.Log;  

public class CrashHandler implements UncaughtExceptionHandler {  

    public static final String TAG = "CrashHandler";  
    private Thread.UncaughtExceptionHandler mDefaultHandler;  
    private static final String OOM = "java.lang.OutOfMemoryError";  
    private static final String HPROF_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/data.hprof";  

    private static CrashHandler sCrashHandler;  

    private CrashHandler() {}  

    public synchronized static CrashHandler getInstance() {  
        if (sCrashHandler == null) {  
            sCrashHandler = new CrashHandler();  
        }  
        return sCrashHandler;  
    }  

    public void init() {  
        mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
        Thread.setDefaultUncaughtExceptionHandler(this);  
    }  

    public static boolean isOOM(Throwable throwable){  
        Log.d(TAG, "getName:" + throwable.getClass().getName());  
        if(OOM.equals(throwable.getClass().getName())){  
            return true;  
        }else{  
            Throwable cause = throwable.getCause();  
            if(cause != null){  
                return isOOM(cause);  
            }  
            return false;  
        }  
    }  

    public void uncaughtException(Thread thread, Throwable throwable) {  
        if(isOOM(throwable)){  
            try {  
                Debug.dumpHprofData(HPROF_FILE_PATH);  
            } catch (Exception e) {  
                Log.e(TAG, "couldn’t dump hprof", e);  
            }  
        }  

        if (mDefaultHandler != null) {  
            mDefaultHandler.uncaughtException(thread, throwable);  
        } else {  
            android.os.Process.killProcess(android.os.Process.myPid());  
            System.exit(1);  
        }  
    }  
}  

最关键的代码是这句

Java 代码 收藏代码
Debug.dumpHprofData(HPROF_FILE_PATH);

使得我们可以自己控制抓取 heap 快照的时机
OutOfMemoryError 是系统级别的错误,所以一般情况下不该捕获它。
万一有人捕获了,并且重新抛出了一个调用了 initCause 方法的异常,我们也应该截获它,然后修正 bug,而不是掩藏它。

我们在这里只是需要抓取内存快照,干完活之后要记得把 throwable 交给系统来处理
Java 代码 收藏代码
mDefaultHandler.uncaughtException(thread, throwable);

当然,我们在这个地方实际上也可以屏蔽掉 force close 对话框,很神奇吧。。。

结尾顺便说一下,如何查看 android 对应用的内存限制
每款手机对应用的限制都是不一样的,毕竟硬件不同,我们可以使用如下方式来查看单独的应用可使用的最大内存:

adb shell getprop | grep heap  
[dalvik.vm.heapgrowthlimit]: [64m]  
[dalvik.vm.heapsize]: [256m]  
[dalvik.vm.heapstartsize]: [8m]  

输入命令之后回查到上述几个结果

更改上述参数可以在 build.prop 修改
build.prop 在 system 下,pull 出来修改后再 push 回去,reboot 即可

我们可以根据这个来估计 heap 的大小,检查 sd 卡剩余空间是否够用。

转贴请保留以下链接
本人 blog 地址
http://su1216.iteye.com/
http://blog.csdn.net/su1216/

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册