LeakCanary:检测所有的oom

没有人喜欢OutOfMemory崩溃

在Square的注册界面,我们使用bitmap缓存绘制客户的签名,使用的bitmap大小等同于屏幕大小,当创建它时,我们有了大量的OOM崩溃。

我们尝试了一些方法,但是没有一个可以解决问题:
  • 使用Bitmap.Config.ALPHA_8(签名不需要颜色)。
  • 捕获OutOfMemoryError,触发GC并多次重试(灵感来源于GCUtils)。
  • 我们没有想过从Java 堆分配位图,幸运的是,Fresco 也没有。(注:Fresco是Facebook用于图片缓存的开源库,可以关注一些)

我们曾看错了方向

bitmap的大小并不是问题,当内存将要用完的时候,OOM可以随处发生。它们更多的发生在你创建一个像Bitmap这种比较大的对象的情况下。OOM只是一个症状源自于更深层次的问题:内存泄露。

什么是内存溢出?

某些对象生命周期有限,当它们的工作完成以后,将会被回收。如果一个对象在其生命周期结束以后仍被内存中引用,将会导致内存泄露。当泄露积累过多,该应用将耗尽内存。

比如,在Activity.OnDestroy()方法被调用以后,这个activity的各种层级视图和它们关联的位图都应该被回收掉,如果一个后台运行的线程有该activity的引用,activity相对应的内存将不能被回收,这最终会导致OutOfMemoryError崩溃。

追踪内存溢出

追踪内存溢出是一个手动过程,   Raizlabs 的  Wrangling Dalvik 对此有很好的描述。

下面是关键步骤:

  1. 通过 BugsnagCrashlytics,或者 Developer Console 了解内存溢出。
  2. 尝试重现该问题。你可能需要通过购买或者借用遇到崩溃问题的特定设备。(并非所有设备都会呈现这些泄漏) !你还需要弄清楚是哪一系列操作触发泄漏,有可能是蛮力。


  3. 当泄露发送时,记录堆栈内容(点击此处获取代码

  4. 使用MAT 或者YourKit 查看堆栈内容,并从中找出应该被回收的对象。

  5. 计算最短到 GC 根从该对象的强引用路径

  6. 找出哪个引用路径不应该存在,并修复内存溢出问题。

该库会在你遇到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);  
  }  
} 
你会得到一个Notification和一个很好的展示界面:



总结

在使用LeakCanary以后,我们在自己的应用中发现了许多内存泄露问题,我们甚至发现了一些Android SDK的内存泄露

结果是令人惊讶的,我们的OOM错误减少了94%。
如果你想消灭OOM错误,现在就使用 LeakCanary 吧!


发布了32 篇原创文章 · 获赞 115 · 访问量 7万+

猜你喜欢

转载自blog.csdn.net/bryant_liu24/article/details/52424103