超贊的OOM檢測(除了mat以外)


今天看了下微博,扔物線分享了個內存檢測的工具:

內存泄露是 OOM 最常見的原因,但它的偵測需人工排查,往往眼看瞎也未必能找到泄露的內存。Square 新庫 LeakCanary 用一種巧妙的思路實現了自動探測內存泄露,這已經幫他們減少了94%的 OOM。 在這篇文中,Square 介紹了這個帥氣的庫,也提出了一種新穎的獲取測試設備的方式:"偷":

是不是這種檢測OOm問題的方式比其MAT來說簡直爽的一逼一逼的。
這是這個檢測工具的官網: https://corner.squareup.com/2015/05/leak-canary.html
開源庫地址:https://github.com/square/leakcanary
一下是相關翻譯:

LeakCanary: Detect all memory leaks!

May 08, 2015
java.lang.OutOfMemoryError
        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)

沒有任何人會喜歡OOM問題的出現

In Square Register, we draw the customer's signature on a bitmap cache. This bitmap is the size of the device's screen, and we had a significant number of out of memory (OOM) crashes when creating it.

這個圖片的大小是設備大小,我們在顯示這個圖片的時候會出現OOM的問題。

We tried a few approaches, none of which solved the issue:

我們嘗試了一些方法,其中沒有解決的問題:

  • Use Bitmap.Config.ALPHA_8 (a signature doesn't need color).
  • 使用bitmap.config.alpha_8
  • Catch OutOfMemoryError, trigger the GC and retry a few times (inspired from GCUtils).
  • 抓住OutOfMemoryError,觸發GC和重試幾次(靈感來自gcutils)。
  • We didn't think of allocating bitmaps off the Java heap. Lucky for us, Fresco didn't exist yet.
  • 我們不想把Java堆分配位圖。幸運的是,Fresco 這個開源項目不存在這種問題。

We were looking at it the wrong way

The bitmap size was not a problem. When the memory is almost full, an OOM can happen anywhere. It tends to happen more often in places where you create big objects, like bitmaps. The OOM is a symptom of a deeper problem: memory leaks.

位圖是沒問題的,如果內存滿的話,一個oom會出現在任何地方。當你創建比較大的對象,像bitmap這種東西的地方就會出現這種問題,oom更深層次的問題就是內存泄漏的問題。

What is a memory leak?

什么是內存泄漏呢?

Some objects have a limited lifetime. When their job is done, they are expected to be garbage collected. If a chain of references holds an object in memory after the end of its expected lifetime, this creates a memory leak. When these leaks accumulate, the app runs out of memory.

許多對象是有有限制的生命周期的,當他們工作完成后,就會被垃圾回收。當對象的引用在對象的生命周期后還在持有該引用的話,就會出現內存泄漏的問題。當引用累計到一定一定時候,就會出現OOM的問題。

For instance, after Activity.onDestroy() is called, the activity, its view hierarchy and their associated bitmaps should all be garbage collectable. If a thread running in the background holds a reference to the activity, then the corresponding memory cannot be reclaimed. This eventually leads to an OutOfMemoryError crash.

例如,在Actiivity ondestroy()后,它的視圖層次結構及其相關的位圖應該都是垃圾收集。如果一個線程在后台運行,持有該activity引用,那么相應的內存不能被回收。這最終導致OutOfMemoryError錯誤,崩潰。

捕獲OOM的問題

Hunting memory leaks is a manual process, well described in Raizlabs’ Wrangling Dalvik series.

捕獲OOM的問題是一個手動的過程。

Here are the key steps:

關鍵步驟如下:

  1. Learn about OutOfMemoryError crashes via BugsnagCrashlytics, or the Developer Console.
  2. 在使用Bugsnag, Crashlytics以及 Developer Console工具去檢測OutOfMemoryError這種問題。 
  3. Attempt to reproduce the problem. You might need to buy, borrow, or steal the specific device that suffered the crash. (Not all devices will exhibit all leaks!) You also need to figure out what navigation sequence triggers the leak, possibly by brute force.
  4. 重現問題,你可能需要購買或者借到一些特殊的設備來重現crash問題(並不是所有的設備都會出現這種問題),你需要知道是什么導致內存泄漏的問題,有可能是蠻力(這句翻譯的有點怪,我擦)。
  5. Dump the heap when the OOM occurs (here's how).
  6. 堆積OOM的問題
  7. Poke around the heap dump with MAT or YourKit and find an object that should have been garbage collected.
  8. 使用MAT或者 YourKit 工具去發現那些對象應該被回收。
  9. Compute the shortest strong reference path from that object to the GC roots.
  10. 計算最短路徑的強引用對象的GC根。
  11. Figure out which reference in the path should not exist, and fix the memory leak.
  12. 找出那些引用是不應該存在的,並處理內存對這些引用。

What if a library could do all this before you even get to an OOM, and let you focus on fixing the memory leak?

如果有一個庫幫助你在oom問題出現之前去檢測OOM的問題,你會去關注如何修復內存引用的問題嗎?

介紹使用LeakCanary

LeakCanary is an Open Source Java library to detect memory leaks in your debug builds.

LeakCanary是一個開源項目,通過java庫去檢測內存泄漏的問題。

Let's look at a cat example:

看下下面的例子:

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;

You create a RefWatcher instance and give it an object to watch:

你創造了一個refwatcher實例,給它一個對象去檢測:

// We expect schrodingerCat to be gone soon (or not), let's watch it.
refWatcher.watch(schrodingerCat);

When the leak is detected, you automatically get a nice leak trace:

當內存檢測的時候,你會檢測到內存的內存的使用的痕跡。

* GC ROOT static Docker.container
* references Box.hiddenCat
* leaks Cat instance

We know you're busy writing features, so we made it very easy to setup. With just one line of code, LeakCanary will automatically detect activity leaks:

public class ExampleApplication extends Application {
  @Override public void onCreate() {
    super.onCreate();
    LeakCanary.install(this);
  }
}

You get a notification and a nice display out of the box:

你能得到通知,並且能夠良好的展示在界面上:

Conclusion

After enabling LeakCanary, we discovered and fixed many memory leaks in our app. We even found a few leaks in the Android SDK.

在啟用的leakcanary,我們能夠發現並修復你APP里面出現的內存泄漏的問題。我們甚至發現了一些 leaks in the Android SDK

The results are amazing. We now have 94% fewer crashes from OOM errors.

結果讓人吃驚,能夠檢測出94%的OOM的問題。

If you want to eliminate OOM crashes, install LeakCanary now!

如果你想消除OOM導致額問題,先學習leakcanary開始
 
我英語是數學老師教的,如果翻譯的不好,請留言指教下我這個小學生,我一定會改正。

 




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM