相關文章
Android性能優化系列
Java虛擬機系列html
若是使用MAT來分析內存問題,會有一些難度,而且效率也不是很高,對於一個內存泄漏問題,可能要進行屢次排查和對比。
爲了可以簡單迅速的發現內存泄漏,Square公司基於MAT開源了LeakCanary。
java
首先配置build.gradle:android
dependencies {
debugCompile 'com.squareup.leakcanary:leakcanary-android:1.5.2'
releaseCompile 'com.squareup.leakcanary:leakcanary-android-no-op:1.5.2'
}複製代碼
接下來在Application加入以下代碼。git
public class LeakApplication extends Application {
@Override public void onCreate() {
super.onCreate();
if (LeakCanary.isInAnalyzerProcess(this)) {//1
// This process is dedicated to LeakCanary for heap analysis.
// You should not init your app in this process.
return;
}
LeakCanary.install(this);
}
}複製代碼
註釋1處的代碼用來進行過濾操做,若是當前的進程是用來給LeakCanary 進行堆分析的則return,不然會執行LeakCanary的install方法。這樣咱們就可使用LeakCanary了,若是檢測到某個Activity 有內存泄露,LeakCanary 就會給出提示。github
第二節的例子代碼只可以檢測Activity的內存泄漏,固然還存在其餘類的內存泄漏,這時咱們就須要使用RefWatcher來進行監控。改寫Application,以下所示。性能優化
public class LeakApplication extends Application {
private RefWatcher refWatcher;
@Override
public void onCreate() {
super.onCreate();
refWatcher= setupLeakCanary();
}
private RefWatcher setupLeakCanary() {
if (LeakCanary.isInAnalyzerProcess(this)) {
return RefWatcher.DISABLED;
}
return LeakCanary.install(this);
}
public static RefWatcher getRefWatcher(Context context) {
LeakApplication leakApplication = (LeakApplication) context.getApplicationContext();
return leakApplication.refWatcher;
}
}複製代碼
install方法會返回RefWatcher用來監控對象,LeakApplication中還要提供getRefWatcher靜態方法來返回全局RefWatcher。
最後爲了舉例,咱們在一段存在內存泄漏的代碼中引入LeakCanary監控,以下所示。微信
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakThread leakThread = new LeakThread();
leakThread.start();
}
class LeakThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(6 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@Override
protected void onDestroy() {
super.onDestroy();
RefWatcher refWatcher = LeakApplication.getRefWatcher(this);//1
refWatcher.watch(this);
}
}複製代碼
MainActivity存在內存泄漏,緣由就是非靜態內部類LeakThread持有外部類MainActivity的引用,LeakThread中作了耗時操做,致使MainActivity沒法被釋放。關於內存泄漏能夠查看Android內存優化(三)避免可控的內存泄漏這篇文章。
在註釋1處獲得RefWatcher,並調用它的watch方法,watch方法的參數就是要監控的對象。固然,在這個例子中onDestroy方法是多餘的,由於LeakCanary在調用install方法時會啓動一個ActivityRefWatcher類,它用於自動監控Activity執行onDestroy方法以後是否發生內存泄露。這裏只是爲了方便舉例,若是想要監控Fragment,在Fragment中添加如上的onDestroy方法是有用的。
運行程序,這時會在界面生成一個名爲Leaks的應用圖標。接下來不斷的切換橫豎屏,這時會閃出一個提示框,提示內容爲:「Dumping memory app will freeze.Brrrr.」。再稍等片刻,內存泄漏信息就會經過Notification展現出來,好比三星S8的通知欄以下所示。
app
Notification中提示了MainActivity發生了內存泄漏, 泄漏的內存爲787B。點擊Notification就能夠進入內存泄漏詳細頁,除此以外也能夠經過Leaks應用的列表界面進入,列表界面以下圖所示。ide
內存泄漏詳細頁以下圖所示。
工具
點擊加號就能夠查看具體類所在的包名稱。整個詳情就是一個引用鏈:MainActiviy的內部類LeakThread引用了LeakThread的this$0
,this$0
的含義就是內部類自動保留的一個指向所在外部類的引用,而這個外部類就是詳情最後一行所給出的MainActiviy的實例,這將會致使MainActivity沒法被GC,從而產生內存泄漏。
除此以外,咱們還能夠將 heap dump(hprof文件)和info信息分享出去,以下圖所示。
須要注意的是分享出去的hprof文件並非標準的hprof文件,還須要將它轉換爲標準的hprof文件,這樣纔會被MAT識別從而進行分析,關於MAT能夠查看Android內存優化(五)詳解內存分析工具MAT這篇文章。
解決方法就是將LeakThread改成靜態內部類。
public class MainActivity extends AppCompatActivity {
...
static class LeakThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(6 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
...
}複製代碼
再次運行程序LeakThread就不會給出內存泄漏的提示了。
參考資料
《高性能Android應用開發》
使用LeakCanary檢測安卓中的內存泄漏(實戰)
github.com/square/leak…
LeakCanary 中文使用說明
Android 源碼系列之<十三>從源碼的角度深刻理解LeakCanary的內存泄露檢測機制(中)
歡迎關注個人微信公衆號,第一時間得到博客更新提醒,以及更多成體系的Android相關原創技術乾貨。
掃一掃下方二維碼或者長按識別二維碼,便可關注。