文章: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
,简称OOM
。git
当时,咱们尝试过一些解决方案,但都没解决问题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 系列文章中有详细描述。
如下几个关键步骤:
经过 Bugsnag, Crashlytics 或者 Developer Console 等统计平台,了解 OutOfMemoryError
状况。
重现问题。为了重现问题,机型很是重要,由于一些问题只在特定的设备上会出现。为了找到特定的机型,你须要想尽一切办法,你可能须要去买,去借,甚至去偷。 固然,为了肯定复现步骤,你须要一遍一遍地去尝试。一切都是很是原始和粗暴的。
在发生内存泄露的时候,把内存 Dump 出来。具体看这里。
计算这个对象到 GC roots 的最短强引用路径。
肯定引用路径中的哪一个引用是不应有的,而后修复问题。
很复杂对吧?
若是有一个类库能在发生 OOM 以前把这些事情所有都搞定,而后你只要修复这些问题就行了,岂不妙哉!
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 报告:
咱们知道,你很忙,天天都有一大堆需求。因此咱们把这个事情弄得很简单,你只须要添加一行代码就好了。而后 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
相关连接:
一个很是简单的 LeakCanary demo: https://github.com/liaohuqiu/leakcanary-demo