内存泄露从入门到精通三部曲之排查方法篇

标签: python javascript | 发表时间:2015-11-13 08:27 | 作者:腾讯Bugly
分享到:
出处:http://segmentfault.com/blogs

腾讯Bugly特约作者: 姚潮生

最原始的内存泄露测试

重复多次操作关键的可疑的路径,从内存监控工具中观察内存曲线,是否存在不断上升的趋势且不会在程序返回时明显回落。
这种方式可以发现最基本,也是最明显的内存泄露问题,对用户价值最大,操作难度小,性价比极高。


MAT内存分析工具

2.1 MAT分析heap的总内存占用大小来初步判断是否存在泄露

  1. 在Devices 中,点击要监控的程序。

  2. 点击Devices视图界面中最上方一排图标中的“Update Heap”

  3. 点击Heap视图

  4. 点击Heap视图中的“Cause GC”按钮

  5. 到此为止需检测的进程就可以被监视。

Heap视图中部有一个Type叫做data object,即数据对象,也就是我们的程序中大量存在的类类型的对象。在data object一行中有一列是“Total Size”,其值就是当前进程中所有Java数据对象的内存总量,一般情况下,这个值的大小决定了是否会有内存泄漏。可以这样判断:

进入某应用,不断的操作该应用,同时注意观察data object的Total Size值,正常情况下Total Size值都会稳定在一个有限的范围内,也就是说由于程序中的的代码良好,没有造成对象不被垃圾回收的情况。

所以说虽然我们不断的操作会不断的生成很多对象,而在虚拟机不断的进行GC的过程中,这些对象都被回收了,内存占用量会会落到一个稳定的水平;反之如果代码中存在没有释放对象引用的情况,则data object的Total Size值在每次GC后不会有明显的回落。随着操作次数的增多Total Size的值会越来越大,直到到达一个上限后导致进程被杀掉。

2.2 MAT分析hprof来定位内存泄露的原因所在。

这是出现内存泄露后使用MAT进行问题定位的有效手段。

  1. Dump出内存泄露当时的内存镜像hprof,分析怀疑泄露的类:

  2. 分析持有此类对象引用的外部对象

  3. 分析这些持有引用的对象的GC路径

  4. 逐个分析每个对象的GC路径是否正常

从这个路径可以看出是一个antiRadiationUtil工具类对象持有了MainActivity的引用导致MainActivity无法释放。此时就要进入代码分析此时antiRadiationUtil的引用持有是否合理(如果antiRadiationUtil持有了MainActivity的context导致节目退出后MainActivity无法销毁,那一般都属于内存泄露了)。

2.3 MAT对比操作前后的hprof来定位内存泄露的根因所在。

为查找内存泄漏,通常需要两个 Dump结果作对比,打开 Navigator History面板,将两个表的 Histogram结果都添加到 Compare Basket中去

  1. 第一个HPROF 文件(usingFile > Open Heap Dump ).

  2. 打开Histogram view.

  3. 在NavigationHistory view里 (如果看不到就从Window >show view>MAT- Navigation History ), 右击histogram然后选择Add to Compare Basket .

  4. 打开第二个HPROF 文件然后重做步骤2和3.

  5. 切换到Compare Basket view, 然后点击Compare the Results (视图右上角的红色"!"图标)。

  6. 分析对比结果

可以看出两个hprof的数据对象对比结果。通过这种方式可以快速定位到操作前后所持有的对象增量,从而进一步定位出当前操作导致内存泄露的具体原因是泄露了什么数据对象。

注意:

如果是用 MAT Eclipse 插件获取的 Dump文件,不需要经过转换则可在MAT中打开,Adt会自动进行转换。

而手机SDk Dump 出的文件要经过转换才能被 MAT识别,Android SDK提供了这个工具 hprof-conv (位于 sdk/tools下)

首先,要通过控制台进入到你的 android sdk tools 目录下执行以下命令:

  ./hprof-conv xxx-a.hprof xxx-b.hprof

例如 hprof-conv input.hprof out.hprof
此时才能将out.hprof放在eclipse的MAT中打开。

手机管家内存泄露每日监控方案

目前手机管家的内存泄露每日监控会自动运行并输出是否存在疑似泄露的报告邮件,不论泄露对象的大小。这其中涉及的核心技术主要是AspectJ,MLD自研工具(原理是虚引用)和UIAutomator。

3.1 AspectJ插桩监控代码

手机管家目前使用一个ant脚本加入MLD的监控代码,并通过AspectJ的语法实现插桩。
使用AspectJ的原因是可以灵活分离出项目源码与监控代码,通过不同的编译脚本打包出不同用途的安装测试包:如果测试包是经过Aspect插桩了MLD监控代码的话,那么运行完毕后会输出指定格式的日志文件,作为后续分析工作的数据基础。

3.2 MLD实现监控核心逻辑

这是手机管家内的一个工具工程,正式打包不会打入,BVT等每日监控测试包可以打入。打入后可以通过诸如addObject接口(通过反射去检查是否含有该工具并调用)来加入需要监控的检测对象,这个工具会自动在指定时机(如退出管家)去检测该对象是否发生泄漏。

这个内存泄露检测的基本原理是:

虚引用主要用来跟踪对象被垃圾回收器回收的活动。虚引用必须和引用队列(ReferenceQueue)联合使用(在虚引用函数就必须关联指定)。当垃圾回收器准备回收一个对象时,如果发现它还有虚引用,就会在回收对象的内存之前,自动把这个虚引用加入到与之关联的引用队列中。程序可以通过判断引用队列中是否已经加入了虚引用,来了解被引用的对象是否将要被垃圾回收。

基于以上原理,MLD工具在调用接口addObject加入监控类型时,会为该类型对象增加一个虚引用,注意虚引用并不会影响该对象被正常回收。因此可以在ReferenceQueue引用队列中统计未被回收的监控对象是否超过指定阀值。

利用PhantomReferences(虚引用)和ReferenceQueue(引用队列),当PhantomReferences被加入到相关联的ReferenceQueue时,则视该对象已经或处于垃圾回收器回收阶段了。

MLD监控原理核心

目前手机管家已对大部分类完成内存泄露的监控,包括各种activity,service和view页面等,务求在技术上能带给用户最顺滑的产品体验。

接下来简单介绍下这个工具的判断核心。根据虚引用监控到的内存状态,需要通过多种策略来判断是否存在内存泄露。

  1. 最简单的方式就是直接在加入监控时就为该类型设定最大存在个数,举个例子,各个DAO对象理论上只能存在最多一个,因此一旦出现两个相同的DAO,那一般都是泄露了;

  2. 第二种情况是在页面退出程序退出时,检索gc后无法释放的对象列表,这些对象类型也会成为内存泄露的怀疑对象;

  3. 最后一种情况比较复杂,基本原理是根据历史操作判断对象数量的增长幅度。根据对象的增长通过最小二乘法拟合出该对象类型的增长速度,如果超过经验值则会列入疑似泄露的对象列表。

3.3 UIAutomator完成重复操作的自动化

最后一步就很简单了。这么多反复的UI操作,让人工来点就太浪费人力了。我们使用UIAutomator来进行自动化操作测试。

目前手机管家的每日自动化测试已覆盖各个功能的主路径,并通过配置文件的方式来灵活驱动用例的增删改查,最大限度保证了随着版本推移用例的复用价值。

至此手机管家的内存泄露测试方案介绍完毕,也欢迎各路牛人交流沟通更多更强的内存泄露工具盒方案!


Bugly 是腾讯内部产品质量监控平台的外发版本,其主要功能是App发布以后,对用户侧发生的Crash以及卡顿现象进行监控并上报,让开发同学可以第一时间了解到App的质量情况,及时机型修改。目前腾讯内部所有的产品,均在使用其进行线上产品的崩溃监控。

相关 [内存 三部曲 方法] 推荐:

内存泄露从入门到精通三部曲之排查方法篇

- - SegmentFault 最新的文章
腾讯Bugly特约作者: 姚潮生. 重复多次操作关键的可疑的路径,从内存监控工具中观察内存曲线,是否存在不断上升的趋势且不会在程序返回时明显回落. 这种方式可以发现最基本,也是最明显的内存泄露问题,对用户价值最大,操作难度小,性价比极高. 2.1 MAT分析heap的总内存占用大小来初步判断是否存在泄露.

个人私藏的电影三部曲

- alavinid - 盘点控 – Mtime时光网
土耳其导演赛米的倒叙的一个主角约瑟夫一生的电影三部曲,风格平静缓慢,叙事简朴暗含张力,诸多的诗话长镜头,我的至爱. 格斯范桑特的极简主义实验电影,标志性的长镜头、跟镜头和一如既往的沉默,我的至爱. 2.《方泰尼亚往事三部曲》. 葡萄牙导演佩德罗科斯塔的代表作,实验电影,也是标志性的固定长镜头,灰暗的电影基调,一种近乎残酷的冷峻深刻,颇为震撼.

创业三部曲之一——学技术

- 小宇 - Tech2IPO
我从创立3家科技公司的经历中学到了什么. 36kr 上的这篇文章直截了当的告诉你,作为一个想要成功的创业者,你需要具备哪些素质. 然而,这些素质因人而异,并不是所有创业者都需要从同一个模子里造出来才 能成功. 但是,在与许多创业者接触的交流中,我们发现大家遇到一些共性问题. 这些问题并不是创业者自身素质问题,也并不是无法改变的,而是很多有想法有激 情的创业者不擅长的.

创业三部曲之二——找伙伴

- Frank Cai - Tech2IPO
十几年前,两个技术牛人合作开发出了一个搜索引擎叫Google,现以成为全球最强大使用范围最广的信息工具. 如今,两位创始人一位掌管技术一位是CEO. 这充分说明,要想能够成功运作,即使是一个技术氛围再浓的公司,创始人也需要从技术中走出来,做一些非技术的工作. 在《创业三部曲之一——学技术》一文中我们提到,在互联网行业创业,技术是必不可少的.

营销策略制定的三部曲

- - 互联网的那点事
营销理论多如牛毛,常常学了这个、忘了那个,甚至在真正执行的时候有如瞎子摸象一般,造成多数的营销策略无法产生预期的效果,因此我在这裡试着将营销分为叁块拼图,带大家一窥现代营销的整体面貌,让大家能在短时间内理解并掌握何谓营销?以及应该如何进行策略的拟定. 首先,第一块版图,环境与情况:消费者在什么状况下会想到(使用)你的产品或服务?.

打造高绩效文化三部曲

- - 创业邦
  高级管理者往往认为企业文化很难衡量或者很难改变. 因此,许多人的选择是,不对企业文化领域进行投资——即使有很多事实表明,如果管理者能够有技巧地进行企业文化管理,企业将因此形成竞争性优势,进而成就非凡、经久不衰.   澳大利亚四大银行之一的澳新银行(ANZ Bank),其实践很好地说明了这一点. 十年前,澳新银行采用了一个措施,希望通过一个“有别于传统增长战略的独特计划,达到重塑澳新银行文化以提高效率和盈利的目标”.

jQuery插件编写之三部曲

- - Web前端 - ITeye博客
1、选择一个jQuery框架,如:. //定义你的属性名myPlugin. //使用return this.each运用在多个控件上并实现链式操作. //使用暴露方式设置插件默认参数,这对于让插件的使用者更容易用较少的代码覆盖和修改插件默认设置.  2、添加引用编写好的插件.  首先给你的插件起个名,推荐命名方法为:jquery.[插件名].js,如上面可以命名为jquery.myPlugin.js.

String substring的内存泄漏分析和优化方法

- - ITeye博客
本文将对String.substring方法可能产生内存泄漏的问题进行分析,并给出相应的优化方法. String.substring内存泄漏分析. 首先看一下JDK6 String.substring的源代码:. 从上述的源代码可以看出,使用substring获取子字符串方法中,原有字符串的内容value(char[])将继续重用.

Erlang服务器内存吃紧的优化解决方法

- - CSDN博客系统运维推荐文章
问题提出:服务器100万人在线,16G内存快被吃光. 查看进程数目是否正常,是否超过了erlang虚拟机的最大进程数. 查看节点的内存瓶颈所在地方. 显示内存大部分消耗在进程上,由此确定是进程占用了大量内存. (以输出text方式启动etop,其间隔为1秒,输出行数为20行,按照内存排序. 这里spawn一个新进程,目的是输出etop数据时不影响erlang shell 输入.).