LeakCanary: 让内存泄露无所遁形

09 May 2015


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

java.lang.OutOfMemoryErrorat 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

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

  • 使用 Bitmap.Config.ALPHA_8 因为,签名仅有黑色。

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

  • 我们没想过在 Java heap 内存之外创建 bitmap 。苦逼的我们,那会 Fresco 还不存在。

路子走错了

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

什么是内存泄露

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

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

对战内存泄露

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

以下几个关键步骤:

  1. 通过 Bugsnag, Crashlytics 或者 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

相关链接:

  • LeakCanary 中文使用说明

  • 一个非常简单的 LeakCanary demo: https://github.com/liaohuqiu/leakcanary-demo

  • 本文转自 一点点征服   博客园博客,原文链接:http://www.cnblogs.com/ldq2016/p/6635816.html

  • ,如需转载请自行联系原作者

LeakCanary: 让内存泄露无所遁形相关推荐

  1. 使用LeakCanary检测内存泄露

    前言 刚才在项目里使用LeakCanary检测出了一个使用NotificationBuilder导致的内存泄露,发现LeakCanary真是神器啊.这里转载一篇介绍LeakCanary使用的博客,里面 ...

  2. leaks Android内存泄露,Android LeakCanary 检测内存泄露

    内存泄漏: 指程序在申请内存后 ,无法释放已经申请的内存空间,一次内存泄漏可以忽略,但内存泄漏堆积后果很严重,无论多少内存,都会被占光 内存泄露危害: 1.内存泄露最终会导致内存溢出(OOM) 2.导 ...

  3. LeakCanary——直白的展现Android中的内存泄露

    之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...

  4. 彻底搞懂Java内存泄露

    Java内存回收方式 Java判断对象是否可以回收使用的而是可达性分析算法. 在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的.这个算法的基本思路就是通过一系列名为& ...

  5. JVM内存管理概述与android内存泄露分析

    一.内存划分 将内存划分为六大部分,分别是PC寄存器.JAVA虚拟机栈.JAVA堆.方法区.运行时常量池以及本地方法栈. 1.PC寄存器(线程独有):全称是程序计数寄存器,它记载着每一个线程当前运行的 ...

  6. 全方位带你彻底搞懂Android内存泄露

    1 Java内存回收方式 Java判断对象是否可以回收使用的而是可达性分析算法. 在主流的商用程序语言中(Java和C#),都是使用可达性分析算法判断对象是否存活的.这个算法的基本思路就是通过一系列名 ...

  7. android内存泄漏检测,Android内存泄露检测之LeakCanary的使用

    开始使用 目前为止最新的版本是2.3版本,相比于2.0之前的版本,2.0之后的版本在使用上简洁了很多,只需要在dependencies中加入LeakCanary的依赖即可.而且debugImpleme ...

  8. python 单例模式内存泄露_彻底搞懂Java内存泄露

    之前一直在简书写作,第一次发布到SF上来,也是第一次使用SF,后面会尽量同步到SF,更多文章请关注: 简书 编程之乐 转载请注明出处:谢谢! Java内存回收方式 Java判断对象是否可以回收使用的而 ...

  9. LeakCanary——消除Android中的内存泄露

    2019独角兽企业重金招聘Python工程师标准>>> ##LeakCanary ####简介 LeakCanary是Square公司最近公布的开源项目,旨在消除Android中的内 ...

最新文章

  1. CUDA是Nvidia开发的一种并行计算平台和编程模型,用于在其自己的GPU(图形处理单元)上进行常规计算
  2. openStack 云平台管理节点管理网口流量非常大 出现丢包严重 终端总是时常中断问题调试及当前测试较有效方案...
  3. html以及css的部分相关内容及运用
  4. Linux怎么查看设置系统语言包
  5. docker安装gamit_Gamit-Globk完整安装攻略
  6. leetcode 598. Range Addition II | 598. 范围求和 II
  7. qt 添加依赖库lib_在QT中添加LIB的方法
  8. 提高级:初等数论 威尔逊定理
  9. 实验十一 团队作业7:团队项目设计完善编码
  10. Apache查看并发及TIME_WAIT过多的解决
  11. 2021-06-27Date时间
  12. java 性能优化:35 个小细节,让你提升 java 代码的运行效率
  13. 破解密码很难?利用Python自动编写暴力破解字典,***必学技能!
  14. 图像处理边缘处理:Roberts算子和canny算子,对圆与矩阵进行识别
  15. 温控PLC三菱风机程序设计多路多路风机,温度控制,时间控制
  16. python+Aritest自动化——03—test_cace.py—写自动化测试用例
  17. c语言计算矩阵的n次方,N矩阵的n次方运算及折半查找报告--数据结构(C语言)
  18. 车载娱乐系统开发术语记录
  19. Android 蓝牙HOGP协议(基于ble-gatt蓝牙)连接流程分析--framework-jni-btif-bta-btm-hci -- 全网最详细(二)
  20. ssh “Missing privilege separation directory: /run/sshd“

热门文章

  1. 优秀的领导与差劲的领导
  2. 史丹利对话中国农民丰收节交易会-万祥军:谋定跨国合作
  3. Mybatis学习第一天——Mybatis的安装配置以及基本CURD操作
  4. MonkeyServer的使用及自动化
  5. 获取用户真实Ip地址
  6. HTML5 Web app开发工具Kendo UI Web中Grid网格控件的使用
  7. 设计模式学习(六)结构型模式初步了解
  8. PMcaff-活动| 产品经理免费培训最后一批通过名单公布啦!
  9. 【转载】ubuntu下/usr/bin和/usr/local/bin的区别
  10. ThinkJava-复用类