(這裏不教你如何分析heap快照,只說明如何在關鍵時候抓取)

首先說一下,在程序沒有崩溃的時候如何抓取heap快照。

這個大家應該都知道,在ddms中自帶此功能。

1346038726_7730  

見上圖

首先我們選中一個進程,然後點擊 Update Heap按鈕(小綠蟲子旁邊的按鈕),這時就能看到heap使用情況

如果想取出快照詳細分析,我們可以點擊 Dump HPROF File按鈕,保存到電腦上面。使用android-sdk/tools/hprof-conv這個工具把文件轉換一下,之後用MAT分析即可。

hprof-conv '/home/su1216/data.hprof' '/home/su1216/data_ok.hprof'

這時MAT能直接打開data_ok.hprof文件。

 

 

如果想要OOM時的內存快照該怎麼辦,我們總不能緊盯着手機的同時再盯着電腦,OOM出現的瞬間抓取內存快照,這顯然是不現實的。

如果OOM並不經常复現,那麼我們會錯過很多修改bug的機會,浪費很多時間。

 

下面给大家一種抓取OOM時的heap快照的方法

由於OOM時的heap快照較大,所以抓取的內存快照我選擇保存到sd卡中,因此要有寫入外部存儲的權限

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

然後我們需要實現UncaughtExceptionHandler這個接口

記得要設置未捕獲異常的Handler,設置为自己。

當出現了異常的時候,uncaughtException方法會被調用,所以如果我們可以在這裏抓取內存快照。

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);
		}
	}
}

最關鍵的代碼是這句

Debug.dumpHprofData("/sdcard/data.hprof");

使得我們可以自己控制抓取heap快照的時機

OutOfMemoryError是系統級別的錯誤,所以一般情況下不該捕獲它。

萬一有人捕獲了,並且重新拋出了一個調用了initCause方法的異常,我們也應該截獲它,然後修正bug,而不是掩藏它。

 

我們在這裏只是需要抓取內存快照,幹完活之後要記得把throwable交给系統來處理

mDefaultHandler.uncaughtException(thread, throwable);

當然,我們在這個地方實際上也可以屏蔽掉force close對話框,很神奇吧。。。

 

結尾順便說一下,如何查看android對應用的內存限制

每款手機對應用的限制都是不一样的,畢竟硬件不同,我們可以使用如下方式來查看單獨的應用可使用的最大內存:

adb shell getprop | grep heap
[dalvik.vm.heapgrowthlimit]: [64m]
[dalvik.vm.heapsize]: [256m]
[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卡剩餘空間是否夠用。


From:CSDN        

 




創作者介紹
創作者 shadow 的頭像
shadow

資訊園

shadow 發表在 痞客邦 留言(0) 人氣()