LeakCanary: 让内存泄露无所遁形
LeakCanary: 让内存泄露无所遁形
09 May 2015
本文为LeakCanary: Detect all memory leaks!的翻译。原文在: https://corner.squareup.com/2015/05/leak-canary.html
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。

当时,我们尝试过一些解决方案,但都没解决问题
使用 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 系列文章中有详细描述。
以下几个关键步骤:
通过 Bugsnag, Crashlytics 或者 Developer Console 等统计平台,了解
OutOfMemoryError情况。重现问题。为了重现问题,机型非常重要,因为一些问题只在特定的设备上会出现。为了找到特定的机型,你需要想尽一切办法,你可能需要去买,去借,甚至去偷。 当然,为了确定复现步骤,你需要一遍一遍地去尝试。一切都是非常原始和粗暴的。
在发生内存泄露的时候,把内存 Dump 出来。具体看这里。
计算这个对象到 GC roots 的最短强引用路径。
确定引用路径中的哪个引用是不该有的,然后修复问题。
很复杂对吧?
如果有一个类库能在发生 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 demo: https://github.com/liaohuqiu/leakcanary-demo
LeakCanary: 让内存泄露无所遁形的更多相关文章
- 使用LeakCanary检测内存泄露 翻译 MD
Markdown版本笔记 我的GitHub首页 我的博客 我的微信 我的邮箱 MyAndroidBlogs baiqiantao baiqiantao bqt20094 baiqiantao@sina ...
- Android内存优化8 内存检测工具2 LeakCanary——直白的展现Android中的内存泄露
之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...
- LeakCanary——直白的展现Android中的内存泄露
之前碰到的OOM问题,终于很直白的呈现在我的眼前:我尝试了MAT,但是发现不怎么会用.直到今天终于发现了这个新工具: 当我们的App中存在内存泄露时会在通知栏弹出通知: 当点击该通知时,会跳转到具体的 ...
- Android性能优化之利用LeakCanary检测内存泄漏及解决办法
前言: 最近公司C轮融资成功了,移动团队准备扩大一下,需要招聘Android开发工程师,陆陆续续面试了几位Android应聘者,面试过程中聊到性能优化中如何避免内存泄漏问题时,很少有人全面的回答上来. ...
- JVM内存管理概述与android内存泄露分析
一.内存划分 将内存划分为六大部分,分别是PC寄存器.JAVA虚拟机栈.JAVA堆.方法区.运行时常量池以及本地方法栈. 1.PC寄存器(线程独有):全称是程序计数寄存器,它记载着每一个线程当前运行的 ...
- [转]深入Android内存泄露
深入内存泄露 Android应用的内存泄露,其实就是java虚拟机的堆内存泄漏. 当然,当应用有ndk,jni时,没有及时free,本地堆也会出现内存泄漏. 本文只是针对JVM内存泄漏应用,进行阐述分 ...
- LeakCanary Android 和 Java 内存泄露检测。
开始使用 在 build.gradle 中加入引用,不同的编译使用不同的引用: dependencies { debugCompile 'com.squareup.leakcanary:leakcan ...
- 内存测试——内存泄露工具 LeakCanary
项目地址 https://github.com/square/leakcanary 接入方法 1. 配置依赖 dependencies { debugCompile 'com.squareup.lea ...
- LeakCanary Android 和 Java 内存泄露检测
说起内存泄漏还是挺让人头疼的,而且不是每个手机都会发生的情况,往往又不易察觉,那么今天我们就来介绍下LeakCanary这个工具 githup:https://github.com/square/le ...
随机推荐
- 【Single Num II】cpp
题目: Given an array of integers, every element appears three times except for one. Find that single o ...
- LeetCode 62 不同路径
一个机器人位于一个 m x n 网格的左上角 (起始点在下图中标记为“Start” ).机器人每次只能向下或者向右移动一步.机器人试图达到网格的右下角.问总共有多少条不同的路径? 示例 1: 输入: ...
- PAT——乙级1001and1011
准备明年年初考PAT,练题呀,暂且先把LeetCode放下. 我是按照算法笔记这个教材刷的. B1001 1001 害死人不偿命的(3n+1)猜想 (15 point(s)) 卡拉兹(Callatz) ...
- 历史Linux镜像的问题修复方案
历史Linux镜像创建的ECS云服务器,可能存在NTP没有配置,YUM没有配置,还可能存在最近暴漏较高的安全漏洞,请按照以下步骤进行修复,可以让您的云服务器更加安全,还可以使用阿里云提供的YUM服务进 ...
- 如何通过IP地址分辨公网、私网、内网、外网
如何通过IP地址分辨公网.私网.内网.外网 内.外网是相对于防火墙而言的,在防火墙内部叫做内网,反之就是外网. 在一定程度上外网等同于公网,内网等同于私网. 地址为如下3个区域就是处于私网 ...
- ci支持pathinfo
location ~ \.php { #去掉$ root H:/PHPServer/WWW; fastcgi_pass ; fastcgi_index index.php; fastcgi_split ...
- jupyter的使用
shift+enter 运行程序 Tab 代码补全 shift+Tab 查看函数说明 shift+Tab+Tab 查看函数详细说明 https://www.dataquest.io/blog/jupy ...
- manifest
manifest是一种软件,属于AndroidManifest.xml文件,在简单的Android系统的应用中提出了重要的信息,它可以运行任何应用程序的代码. 每个安卓应用程序必须有一个Android ...
- pat 甲级 1034. Head of a Gang (30)
1034. Head of a Gang (30) 时间限制 100 ms 内存限制 65536 kB 代码长度限制 16000 B 判题程序 Standard 作者 CHEN, Yue One wa ...
- nginx报404的可能错误
1.转移地址写错,如root E:software_setup\ftpfile,而你实际的目录地址(比如test.jpg)在ftpfile文件夹里面的img文件夹下,如果直接找ftpfile\test ...