摘要:前兩天,開源了一個內(nèi)存泄露自動探測神器,它是一個和的內(nèi)存泄露檢測庫,可以大幅度減少了開發(fā)中遇到的問題,對于開發(fā)者來說,無疑是個福音,下面對該庫的進(jìn)行簡單的翻譯小漏不補(bǔ)沉大船。隨著時間過去越來越多熟知的內(nèi)存泄露問題被制造商在開源項目中修復(fù)。
前兩天,Square開源了一個內(nèi)存泄露自動探測神器——LeakCanary,它是一個Android和Java的內(nèi)存泄露檢測庫,可以大幅度減少了開發(fā)中遇到的OOM問題,對于開發(fā)者來說,無疑是個福音,下面對該庫的readme進(jìn)行簡單的翻譯:
“A small leak will sink a great ship.” - Benjamin Franklin
小漏不補(bǔ)沉大船。——本杰明 富蘭克林
在項目的build.gradle文件添加:
dependencies { debugCompile "com.squareup.leakcanary:leakcanary-android:1.3" releaseCompile "com.squareup.leakcanary:leakcanary-android-no-op:1.3" }
在Application類添加:
public class ExampleApplication extends Application { @Override public void onCreate() { super.onCreate(); LeakCanary.install(this); } }
當(dāng)在你的debug構(gòu)建過程中出現(xiàn)內(nèi)存泄露時,LeakCanary將會自動展示一個通知欄。
為什么我應(yīng)該使用LeakCanary?問得好!我們正好寫了個博客回答這個問題。
那怎么使用它呢?使用一個RefWatcher觀察引用什么時候應(yīng)該被GC:
RefWatcher refWatcher = {...}; // We expect schrodingerCat to be gone soon (or not), let"s watch it. refWatcher.watch(schrodingerCat);
LeakCanary.install() 返回一個先前配置的RefWatcher,它也安裝一個ActivityRefWatcher以便在Activity.onDestroy()被調(diào)用后自動檢測Activity是否出現(xiàn)泄露。
public class ExampleApplication extends Application { public static RefWatcher getRefWatcher(Context context) { ExampleApplication application = (ExampleApplication) context.getApplicationContext(); return application.refWatcher; } private RefWatcher refWatcher; @Override public void onCreate() { super.onCreate(); refWatcher = LeakCanary.install(this); } }
你可以使用RefWatcher觀察Fragment的內(nèi)存泄露
public abstract class BaseFragment extends Fragment { @Override public void onDestroy() { super.onDestroy(); RefWatcher refWatcher = ExampleApplication.getRefWatcher(getActivity()); refWatcher.watch(this); } }How does it work?
1.RefWatcher.watch()創(chuàng)建一個KeyedWeakReference去檢測對象;
2.接著,在后臺線程,它將會檢查是否有引用在不是GC觸發(fā)的情況下需要被清除的;
3.如果引用引用仍然沒有被清除,將會轉(zhuǎn)儲堆到.hprof文件到系統(tǒng)文件中(it them dumps the heap into a .hprof file stored on the app file system.)
4.HeapAnalyzerService是在一個分離的進(jìn)程中開始的,HeapAnalyzer通過使用HAHA解析heap dump;
5.由于一個特殊的引用key和定位的泄露引用,HeapAnalyzer可以在heap dump中找到KeyedWeakReference;
6.如果有一個泄露,HeapAnalyzer計算到GC Roots的最短的強(qiáng)引用路徑,然后創(chuàng)建造成泄露的引用鏈;
7.結(jié)果在app的進(jìn)程中傳回到DisplayLeakService,并展示泄露的通知消息;
你可以在Logcat上看leak trace:
In com.example.leakcanary:1.0:1 com.example.leakcanary.MainActivity has leaked: * GC ROOT thread java.lang.Thread.(named "AsyncTask #1") * references com.example.leakcanary.MainActivity$3.this$0 (anonymous class extends android.os.AsyncTask) * leaks com.example.leakcanary.MainActivity instance * Reference Key: e71f3bf5-d786-4145-8539-584afaecad1d * Device: Genymotion generic Google Nexus 6 - 5.1.0 - API 22 - 1440x2560 vbox86p * Android Version: 5.1 API: 22 * Durations: watch=5086ms, gc=110ms, heap dump=435ms, analysis=2086ms
你也可以分享leak trace和heap dump文件通過action bar的菜單。
My leak is caused by the SDK implementation!隨著時間過去越來越多熟知的內(nèi)存泄露問題被制造商在android開源項目中修復(fù)。當(dāng)這樣一個泄露發(fā)生時,你能作為一個應(yīng)用程序開發(fā)員來修復(fù)它。出于這個原因,LeakCanary有一個內(nèi)置Android泄露的列表AndroidExcludedRefs.java來監(jiān)測它,如果你找到一個新的泄露,請用leaktrace創(chuàng)建一個issue,標(biāo)明設(shè)備和Android版本。如果你提供一個heap dump的文件鏈接就更好了。
這是對于新發(fā)布的Android版本來說是特別重要的。你有機(jī)會更早地幫助檢測新的內(nèi)存泄露,這有益于整個Android社區(qū)。
開發(fā)版快照可以通過Sonatype"s snapshots repository找到。
有時leak trace不夠清晰,你需要使用MAT和YourKit深入研究heap dump。這里教你怎樣在head dump找到泄露的實例:
1.找出包com.squareup.leakcanary.KeyedWeakReference下所有實例;
2.對于每個實例,考慮它的key域;
3.找到 KeyedWeakReference 有一個key域等于被LeakCanary報出的引用的key;
4.KeyedWeakReference的referent域是程序中內(nèi)存泄露的對象;
5.從那時起,問題就轉(zhuǎn)到你的手上了。一個好的開始是找到最短的GC roots的路徑(排除弱引用)
DisplayLeakActivity自帶一個默認(rèn)的icon和label,可以通過提供的R.drawable.__leak_canary_icon和R.string.__leak_canary_display_activity_label來修改:
res/ drawable-hdpi/ __leak_canary_icon.png drawable-mdpi/ __leak_canary_icon.png drawable-xhdpi/ __leak_canary_icon.png drawable-xxhdpi/ __leak_canary_icon.png drawable-xxxhdpi/ __leak_canary_icon.png
MyLeaks
###儲存leak traces DisplayLeakActivity可以在你的app目錄保存7個heap dumps和leak traces,你可以在app中通過提供R.integer.__leak_canary_max_stored_leaks的值改變這個數(shù)量:20 public class LeakUploadService extends DefaultAnalysisResultService { @Override protected void afterDefaultHandling(HeapDump heapDump, AnalysisResult result, String leakInfo) { if (!result.leakFound || result.excludedLeak) { return; } myServer.uploadLeakBlocking(heapDump.heapDumpFile, leakInfo); } }
###上傳到服務(wù)器 你可以改變默認(rèn)的行為去上傳leak trace并heap dump到你選擇的服務(wù)器。 創(chuàng)建你自己的AbstractAnalysisResultService,最容易的方式是在你debug的源碼中繼承DefaultAnalysisResultService:public class ExampleApplication extends Application { public static RefWatcher getRefWatcher(Context context) { ExampleApplication application = (ExampleApplication) context.getApplicationContext(); return application.refWatcher; } private RefWatcher refWatcher; @Override public void onCreate() { super.onCreate(); refWatcher = installLeakCanary(); } protected RefWatcher installLeakCanary() { return RefWatcher.DISABLED; } }確定在你正式發(fā)布的Application類中使RefWatcher失效:
public class DebugExampleApplication extends ExampleApplication { protected RefWatcher installLeakCanary() { return LeakCanary.install(app, LeakUploadService.class); } }
在你的debug的Application類創(chuàng)建一個定制的RefWatcher:不要忘記了在你debug的manifest中注冊service:
相關(guān)閱讀:內(nèi)存泄露自動探測神器——LeakCanary
譯者:cfanr
轉(zhuǎn)載需說明出處:http://navyifanr.github.io/2015/05/09/LeakCanary-project/
文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/65303.html
摘要:另一種方式就是是一個簡單的,方便的內(nèi)存檢測工具,可以輕易的發(fā)現(xiàn)內(nèi)存問題,還會生成更加簡單清晰的報告。是一個開源的檢測內(nèi)存泄露的庫。 在開發(fā)Android應(yīng)用的過程中如果需要處理圖片或者大量數(shù)據(jù)的時候,就有可能會遇到OOM(java.lang.OutOfMemoryError),一般出現(xiàn)最多的是在創(chuàng)建Bitmap上,也有可能是在內(nèi)存中處理了大量的數(shù)據(jù)上。出現(xiàn)OOM應(yīng)用會直接崩潰,即使沒有...
閱讀 2322·2021-11-24 09:39
閱讀 3055·2021-10-15 09:39
閱讀 3106·2021-07-26 23:38
閱讀 2301·2019-08-30 11:14
閱讀 3420·2019-08-29 16:39
閱讀 1723·2019-08-29 15:23
閱讀 791·2019-08-29 13:01
閱讀 2673·2019-08-29 12:29