LeakCanary: 让内存泄露无所遁形

文章:http://www.jianshu.com/p/7db231163168html

github:https://github.com/square/leakcanaryjava

本文为LeakCanary: Detect all memory leaks!的翻译。原文在: https://corner.squareup.com/2015/05/leak-canary.htmlandroid

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)

谁也不会喜欢 OutOfMemoryError

在 Square Register 中, 在签名页面,咱们把客户的签名画在 bitmap cache 上。 这个 bitmap 的尺寸几乎和屏幕的尺寸同样大,在建立这个 bitmap 对象时,常常会引起 OutOfMemoryError,简称OOMgit

当时,咱们尝试过一些解决方案,但都没解决问题github

  • 使用 Bitmap.Config.ALPHA_8 由于,签名仅有黑色。app

  • 捕捉 OutOfMemoryError, 尝试 GC 并重试(受 GCUtils 启发)。eclipse

  • 咱们没想过在 Java heap 内存以外建立 bitmap 。苦逼的咱们,那会 Fresco 还不存在。ide

路子走错了

其实 bitmap 的尺寸不是真正的问题,当内存吃紧的时候,处处都有可能引起 OO。在建立大对象,好比 bitmap 的时候,更有可能发生。OOM 只是一个表象,更深层次的问题多是: 内存泄露工具

什么是内存泄露

一些对象有着有限的生命周期。当这些对象所要作的事情完成了,咱们但愿他们会被回收掉。可是若是有一系列对这个对象的引用,那么在咱们期待这个对象生命周期结束的时候被收回的时候,它是不会被回收的。它还会占用内存,这就形成了内存泄露。持续累加,内存很快被耗尽。post

好比,当 Activity.onDestroy 被调用以后,activity 以及它涉及到的 view 和相关的 bitmap 都应该被回收。可是,若是有一个后台线程持有这个 activity 的引用,那么 activity 对应的内存就不能被回收。这最终将会致使内存耗尽,而后由于 OOM 而 crash。

对战内存泄露

排查内存泄露是一个全手工的过程,这在 Raizlabs 的 Wrangling Dalvik 系列文章中有详细描述。

如下几个关键步骤:

  1. 经过 BugsnagCrashlytics 或者 Developer Console 等统计平台,了解 OutOfMemoryError 状况。

  2. 重现问题。为了重现问题,机型很是重要,由于一些问题只在特定的设备上会出现。为了找到特定的机型,你须要想尽一切办法,你可能须要去买,去借,甚至去偷。 固然,为了肯定复现步骤,你须要一遍一遍地去尝试。一切都是很是原始和粗暴的。

  3. 在发生内存泄露的时候,把内存 Dump 出来。具体看这里

  4. 而后,你须要在 MAT 或者 YourKit 之类的内存分析工具中反复查看,找到那些本来该被回收掉的对象。

  5. 计算这个对象到 GC roots 的最短强引用路径。

  6. 肯定引用路径中的哪一个引用是不应有的,而后修复问题。

很复杂对吧?

若是有一个类库能在发生 OOM 以前把这些事情所有都搞定,而后你只要修复这些问题就行了,岂不妙哉!

LeakCanary

LeakCanary 是一个检测内存泄露的开源类库。你能够在 debug 包种轻松检测内存泄露。

先看一个例子:

class Cat {
}

class Box {
  Cat hiddenCat;
}
class Docker {
    // 静态变量,将不会被回收,除非加载 Docker 类的 ClassLoader 被回收。
    static Box container;
}

// ...

Box box = new Box();

// 薛定谔之猫
Cat schrodingerCat = new Cat();
box.hiddenCat = schrodingerCat;
Docker.container = box;

建立一个RefWatcher,监控对象引用状况。

// 咱们期待薛定谔之猫很快就会消失(或者不消失),咱们监控一下
refWatcher.watch(schrodingerCat);

当发现有内存泄露的时候,你会看到一个很漂亮的 leak trace 报告:

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

咱们知道,你很忙,天天都有一大堆需求。因此咱们把这个事情弄得很简单,你只须要添加一行代码就好了。而后 LeakCanary 就会自动侦测 activity 的内存泄露了。

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

而后你会在通知栏看到这样很漂亮的一个界面:

结论

使用 LeakCanary 以后,咱们修复了咱们 APP 中至关多的内存泄露。咱们甚至发现了 Android SDK 中的一些内存泄露问题

结果是惊艳的,咱们减小了 94% 的由 OOM 致使的 crash。

若是你也想消灭 OOM crash,那还犹豫什么,赶快使用 LeakCanary

相关连接:

相关文章
相关标签/搜索