LeakCanary:Android和Java的內存泄漏檢測庫。
java.lang.<a href="http://javakk.com/tag/outofmemoryerror" title="查看更多關於 OutOfMemoryError 的文章" target="_blank">OutOfMemoryError</a>
at android.graphics.Bitmap.nativeCreate(Bitmap.java:-2)
at android.graphics.Bitmap.createBitmap(Bitmap.java:689)
at com.squareup.ui.SignView.createSignatureBitmap(SignView.java:121)
沒有人喜歡 **OutOfMemoryError **崩潰
在正方形寄存器中,我們在位圖緩存上繪製客戶的簽名。這個位圖是設備屏幕的大小,我們在創建它時發生了大量的內存不足(OOM)崩潰。
我們嘗試了幾種方法,但都沒有解決問題:
- 使用Bitmap.Config.ALPHA_8(簽名不需要顏色)。
- 捕獲OutOfMemoryError,觸發GC並重試幾次(靈感來自GCUtils)。
- 我們沒有想過從Java堆中分配位圖。我們還不幸運。
我們看錯了
位圖大小不是問題。當內存幾乎滿的時候,OOM可以發生在任何地方。在創建大對象(如位圖)的地方,這種情況更容易發生。OOM是一個更深層次問題的徵兆: **內存泄漏 **。
什麼是內存泄漏?
某些對象的壽命有限。當他們的工作完成後,他們會被垃圾收集起來。如果一個引用鏈在一個對象的預期生存期結束後將其保存在內存中,這將導致內存泄漏。當這些漏洞累積起來時,應用程序的內存就會耗盡。
例如,在調用 Activity.onDestroy() 時,其視圖層次結構及其關聯的位圖都應該是可垃圾回收的。如果在後臺運行的線程持有對活動的引用,則無法回收相應的內存。這最終導致OutOfMemoryError崩潰。
定位內存泄漏
查找內存泄漏是一個手動過程,以下是關鍵步驟:
- 通過Bugsnag、Crashlytics或開發人員控制檯瞭解OutOfMemoryError崩潰。
- 試圖重現問題。您可能需要購買、借用或竊取發生崩潰的特定設備。(並非所有設備都會出現泄漏!)您還需要弄清楚是什麼導航序列觸發了泄漏,可能是暴力造成的。
- 當OOM發生時轉儲堆。
- 用MAT或YourKit在垃圾堆周圍搜索,找到一個應該被垃圾收集的對象。
- 從強引用計算最短路徑。
- 找出路徑中不應存在的引用,並修復內存泄漏。
如果一個庫可以在你到達OOM之前完成所有這些,讓你專注於修復內存泄漏呢?
引進 LeakCanary
LeakCanary是一個開源Java庫,用於檢測調試版本中的內存泄漏。
讓我們看一個貓的例子:
class Cat {
}
class Box {
Cat hiddenCat;
}
class Docker {
static Box container;
}
// ...
Box box = new Box();
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;
創建 RefWatcher 實例併爲其指定要監視的對象:
// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);
當檢測到泄漏時,您會自動獲得一個泄漏跟蹤:
* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance
我們知道你正忙着寫功能,所以我們很容易設置。只需一行代碼,LeakCanary就會自動檢測活動泄漏:
public class ExampleApplication extends Application {
@Override public void onCreate() {
super.onCreate();
LeakCanary.install(this);
}
}
你會得到一個通知和一個很好的開箱即用的顯示:
結論
啓用LeakCanary後,我們發現並修復了應用程序中的許多內存泄漏。我們甚至在Android SDK中發現了一些漏洞。
結果是驚人的。現在,OOM錯誤導致的崩潰減少了94%。
如果你想消除OOM崩潰,現在就安裝LeakCanary!