zoukankan      html  css  js  c++  java
  • android OutOfMemory时抓取heap快照[转]

    (这里不教你如何分析heap快照,只说明如何在关键时候抓取)

    首先说一下,在程序没有崩溃的时候如何抓取heap快照。

    这个大家应该都知道,在ddms中自带此功能。

    见上图

    首先我们选中一个进程,然后点击 Update Heap按钮(小绿虫子旁边的按钮),这时就能看到heap使用情况

    如果想取出快照详细分析,我们可以点击 Dump HPROF File按钮,保存到电脑上面。使用android-sdk/tools/hprof-conv这个工具把文件转换一下,之后用MAT分析即可。

    Java代码  收藏代码
    1. 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代码  收藏代码
    1. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>  

    然后我们需要实现UncaughtExceptionHandler这个接口

    记得要设置未捕获异常的Handler,设置为自己。

    当出现了异常的时候,uncaughtException方法会被调用,所以如果我们可以在这里抓取内存快照。

    Java代码  收藏代码
    1. import java.lang.Thread.UncaughtExceptionHandler;  
    2.   
    3. import android.os.Debug;  
    4. import android.os.Environment;  
    5. import android.util.Log;  
    6.   
    7. public class CrashHandler implements UncaughtExceptionHandler {  
    8.   
    9.     public static final String TAG = "CrashHandler";  
    10.     private Thread.UncaughtExceptionHandler mDefaultHandler;  
    11.     private static final String OOM = "java.lang.OutOfMemoryError";  
    12.     private static final String HPROF_FILE_PATH = Environment.getExternalStorageDirectory().getPath() + "/data.hprof";  
    13.   
    14.     private static CrashHandler sCrashHandler;  
    15.   
    16.     private CrashHandler() {}  
    17.   
    18.     public synchronized static CrashHandler getInstance() {  
    19.         if (sCrashHandler == null) {  
    20.             sCrashHandler = new CrashHandler();  
    21.         }  
    22.         return sCrashHandler;  
    23.     }  
    24.   
    25.     public void init() {  
    26.         mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();  
    27.         Thread.setDefaultUncaughtExceptionHandler(this);  
    28.     }  
    29.   
    30.     public static boolean isOOM(Throwable throwable){  
    31.         Log.d(TAG, "getName:" + throwable.getClass().getName());  
    32.         if(OOM.equals(throwable.getClass().getName())){  
    33.             return true;  
    34.         }else{  
    35.             Throwable cause = throwable.getCause();  
    36.             if(cause != null){  
    37.                 return isOOM(cause);  
    38.             }  
    39.             return false;  
    40.         }  
    41.     }  
    42.       
    43.     public void uncaughtException(Thread thread, Throwable throwable) {  
    44.         if(isOOM(throwable)){  
    45.             try {  
    46.                 Debug.dumpHprofData(HPROF_FILE_PATH);  
    47.             } catch (Exception e) {  
    48.                 Log.e(TAG, "couldn’t dump hprof", e);  
    49.             }  
    50.         }  
    51.   
    52.         if (mDefaultHandler != null) {  
    53.             mDefaultHandler.uncaughtException(thread, throwable);  
    54.         } else {  
    55.             android.os.Process.killProcess(android.os.Process.myPid());  
    56.             System.exit(1);  
    57.         }  
    58.     }  
    59. }  

    最关键的代码是这句

    Java代码  收藏代码
    1. Debug.dumpHprofData(<span style="line-height: 18px; text-align: left;">HPROF_FILE_PATH</span>);  

    使得我们可以自己控制抓取heap快照的时机

    OutOfMemoryError是系统级别的错误,所以一般情况下不该捕获它。

    万一有人捕获了,并且重新抛出了一个调用了initCause方法的异常,我们也应该截获它,然后修正bug,而不是掩藏它。

    我们在这里只是需要抓取内存快照,干完活之后要记得把throwable交给系统来处理

    Java代码  收藏代码
    1. mDefaultHandler.uncaughtException(thread, throwable);  

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

    结尾顺便说一下,如何查看android对应用的内存限制

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

    Shell代码  收藏代码
    1. adb shell getprop | grep heap  
    2. [dalvik.vm.heapgrowthlimit]: [64m]  
    3. [dalvik.vm.heapsize]: [256m]  
    4. [dalvik.vm.heapstartsize]: [8m]  

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

    [dalvik.vm.heapstartsize]: [8m]:给进程分配的起始heap=8m

    [dalvik.vm.heapgrowthlimit]: [64m]:进程最大可分配到64m

    [dalvik.vm.heapsize]: [256m]:单个虚拟机可分配的最大内存=256m

    更改上述参数可以在build.prop修改

    build.prop在system下,pull出来修改后再push回去,reboot即可

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

    转贴请保留以下链接

    本人blog地址

    http://su1216.iteye.com/

    http://blog.csdn.net/su1216/

  • 相关阅读:
    jQuery里的$.ajax()方法详解
    express框架使用axios进行post请求, 两次请求问题
    electron-vue 报错 Unresolved node modules: bufferutil, utf-8-validate, canvas
    electron-vue离线打包
    个推技术:性能提升60%↑ 成本降低50%↓ Spark性能调优看这篇就够了!
    百亿级日志流分析实践 | 剖析个推后效分析功能实现原理
    iOS开发常用国外网站清单
    一篇文章搞定Git——Git代码管理及使用规范
    音视频技术入门——音频处理
    Java内存空间知识点梳理
  • 原文地址:https://www.cnblogs.com/xitang/p/2695759.html
Copyright © 2011-2022 走看看