最原始的内存泄漏测试,多次重复关键可疑路径,从内存监控工具观察内存曲线,是否有上升趋势,不会明显回落到程序返回。这种方法可以找到最基本、最明显的内存泄漏问题,对用户有很大的价值,操作简单,性价比极高。MAT内存分析工具2.1MAT通过分析堆的总内存使用情况初步判断是否存在泄漏。在设备中,单击要监视的程序。单击Devices视图界面中顶行图标中的“UpdateHeap”。单击堆视图。单击堆视图中的“CauseGC”按钮。至此,可以对待检测的过程进行监控。在Heap视图中间,有一个Type叫dataobject,也就是数据对象,也就是我们程序中大量的类类型的对象。在数据对象行中有一列“TotalSize”,它的值是当前进程中所有Java数据对象的总内存。一般这个值的大小决定了是否会发生内存泄漏。可以这样判断:进入一个应用程序,不断运行该应用程序,同时关注数据对象的TotalSize值。一般情况下,TotalSize的值会稳定在一个有限的范围内,也就是说,因为程序中的代码是好的,不存在阻止对象被垃圾回收的条件。所以虽然我们不断的操作会不断的产生很多对象,但是这些对象在虚拟机不断的GC过程中会被回收,内存占用会下降到一个稳定的水平;否则,如果有对象引用没有被释放,每次GC后数据对象的TotalSize值不会明显下降。随着操作次数的增加,TotalSize的值会增加,直到达到上限,进程就会被kill掉。2.2MAT分析hprof定位内存泄漏原因。这是内存泄漏后使用MAT定位问题的有效手段。A)转储内存泄漏时的内存映像hprof,分析疑似泄漏的类:B)分析持有此类对象引用的外部对象C)分析持有引用的这些对象的GC路径D)分析每个对象object一个一个GC路径是否正常?从这个路径可以看出,一个antiRadiationUtil工具类对象持有对MainActivity的引用,从而阻止了MainActivity被释放。此时需要进入代码分析此时antiRadiationUtil的引用是否合理(如果antiRadiationUtil持有MainActivity的上下文,并且MainActivity在程序退出后无法销毁,一般是内存泄漏)。2.3MAT比较运行前后的hprof,定位内存泄漏的根本原因。要查找内存泄漏,通常需要比较两个Dump结果。打开NavigatorHistory面板,将两个表的Histogram结果添加到CompareBasket。A)第一个HPROF文件(使用文件>打开堆转储)。B)打开直方图视图。C)在NavigationHistory视图中(如果看不到它,请转到Window>showview>MAT-NavigationHistory),右键单击直方图并选择AddtoCompareBasket。D)打开第二个HPROF文件并重做步骤2和3.E)切换到比较篮视图,然后单击比较结果(视图右上角的红色“!”图标)。F)分析比较结果,我们可以看到两个hprof数据对象的比较结果。这样可以快速定位操作前后持有对象的增量,从而进一步定位到当前操作导致内存泄漏的具体原因以及泄漏的是什么数据对象。注意:如果Dump文件是用MATEclipse插件获取的,不需要转换就可以在MAT中打开,Adt会自动转换。但是手机SDKDump中的文件必须经过转换才能被MAT识别。AndroidSDK提供了这个工具hprof-conv(位于sdk/tools下)。首先,通过控制台进入你的androidsdktools目录,执行如下命令:./hprof-convxxx-a.hprofxxx-b.hprof比如hprof-convinput.hprofout.hprof然后就可以打开out了.hprof在eclipse的MAT中。手机管家内存泄漏日常监控解决方案目前,手机管家的内存泄漏日常监控会自动运行并输出疑似泄漏的报告邮件,无论泄漏对象大小。涉及的核心技术主要有AspectJ、MLD自研工具(原理是幻引用)和UIAutomator。3.1AspectJ插桩监控代码手机管家目前使用ant脚本添加MLD监控代码,通过AspectJ语法实现插桩。之所以使用AspectJ,是因为它可以灵活地将项目源码和监控代码分开,通过不同的编译脚本打包不同用途的安装测试包:如果测试包通过Aspect插入到MLD监控代码中,会输出指定格式的日志文件作为后续分析的数据依据。3.2MLD实现监控核心逻辑这是手机管家中的一个工具项目。官方包中不会打入,但可以打入BVT等日常监控测试包。进入后,可以通过addObject接口添加需要监控的检测对象(检查是否包含该工具,通过反射调用),该工具会在指定时间(如退出时)自动检测该对象是否泄漏管家)。这种内存泄漏检测的基本原理是幻象引用主要用于跟踪垃圾收集器回收对象的活动。幻象引用必须与引用队列(ReferenceQueue)结合使用(必须与幻象引用函数关联)。当垃圾回收器要回收一个对象时,如果发现它还有一个虚引用,它会自动把这个虚引用添加到与之关联的引用队列中,然后再回收该对象的内存。程序可以通过判断引用队列中是否加入了幻引用来获知被引用对象是否会被垃圾回收。基于以上原理,MLD工具在调用addObject接口添加监控类型时,会为该类型的对象添加一个幻象引用。注意幻象引用不会影响对象的正常回收。因此可以统计ReferenceQueue引用队列中未被回收的监控对象是否超过指定阈值。使用PhantomReferences(虚引用)和ReferenceQueue(引用队列),当PhantomReferences被添加到关联的ReferenceQueue中时,该对象就被认为已经或正处于垃圾回收器回收阶段。MLD监控原理核心目前,手机管家已经完成了大部分品类的内存泄漏监控,包括各类Activity、Services、View页面,从技术上为用户提供最流畅的产品体验。下面简单介绍一下这个工具的判断核心。根据幻象引用监控的内存状态,需要采用多种策略来判断是否存在内存泄漏。(1)最简单的方法是在添加监控的时候直接设置该类型的最大存在数。比如每个DAO对象理论上最多只能存在一个,所以一旦出现两个一模一样的DAO,那一般就是泄露了;(2)第二种情况是页面退出,程序退出时,检索gc后不能释放的对象列表,这些对象类型也会成为内存泄漏的疑似对象;(3)***First这种情况比较复杂,基本原理是根据历史操作来判断对象数量的增长速度。根据物体的生长情况,用最小二乘法拟合物体类型的增长率。如果超过经验值,将被列入疑似泄露对象列表。3.3UIAutomator完成重复操作的自动化第一步很简单。如此多的重复UI操作,如果手动去做,很浪费人力。我们使用UIAutomator进行自动化运行测试。目前,手机管家的日常自动化测试已经覆盖了各个功能的主要路径,并通过配置文件灵活驱动用例的增删改查,随着版本的变化最大化用例的复用价值。至此,手机管家的内存泄漏测试方案介绍完毕,欢迎各位高手交流,获取更多更强的内存泄漏工具箱解决方案!腾讯Bugly简介Bugly是腾讯内部产品质量监控平台的外挂版。其主要功能是监控并上报App上线后用户端发生的崩溃、卡顿等情况,以便开发者第一时间了解App。质量情况,及时修改机型。目前,腾讯所有内部产品都在使用它来监控线上产品的崩溃。
