android 内存查找字符串,Android内存监控与分析三部曲(实例演示)

原标题:Android内存监控与分析三部曲(实例演示)

Gloryroad

新书速递

吴老师的java版《selenium webdriver 实战宝典》和python版《selenium Webdriver 3.0 自动化测试框架实战指南》出版了,代码拿来就能用。

作者:马华平

阅读提示:

--最常遇见的内存泄漏测试场景

--Java内存管理机制

--Android的内存管理

APP测试中难免会有各种显式或者隐式的内存泄漏(Memory Leak)问题,如果不及时发现处理,可能会因为内存泄漏导致各种奇怪的问题(如,卡顿和闪退),甚至可能出现因内存不足(Out of Memory,简称OOM)而导致APP崩溃。

本文分为三部分,通过实战分析内存泄漏和内存溢出问题,并在必要时说明原理或机制。三部曲快速准确定位常见的内存问题。即,

(一)内存泄漏与内存溢出的表现形式和最常遇见的内存泄漏测试场景

(二)分析内存泄漏的原理

(三)内存分析实例演示

34c5d35f09cdefe0ee192fb9161fa5de.png

图1 内存监控与分析

内存分析实例演示

一、内存测试流程中的要点

1. 代码

通常用来进行内存测试的版本是纯净版本,不应该附加多余的Log和调试用组件。例如有些情况下,为了测试界面延迟/函数执行时间等性能,会加入一些桩点代码。在内存测试中这些代码是不必要的,它们可能会分配临时内存,引起更多的GC,导致应用出现运行缓慢、卡顿等现象。

2. 测试场景

测试场景通常有两类。

一类是当前有新开发或改动的某项功能,需要对该功能进行性能测试。因此测试场景主要针对该功能组织,包括功能的开启前、运行、结束后等测试点。

另一类是整体性能,考察应用的常见场景,在综合使用情况下的性能指标。测试场景应当包括启动后待机,切换到后台,执行主要功能,以及反复执行各功能后。

在各类场景中,经常作为测试重点的有:

包含了图片显示的界面。

网络传输大量数据。

需要缓存数据的场景。

3. 场景转换成用例

选取了测试场景后,用例设计也要考虑内存测试的特点。一些常见的方法是:

结合场景比较操作前后或不同版本的内存变化。

显示多张图片的前台进程。

多个场景来回切换。

长时间运行进程的内存增长。

4. 执行

由于GC和广播机制的存在,应用内存通常都在不停地波动,幅度可能会达到几百KB,因此执行时需要考虑这种情况。在采集数据时,需要多次采集并计算平均值。

执行完成,我们就可以根据数据进行比较初步的分析以确定方向。一方面是我们熟悉的Dalvik Heap部分,即由Java代码直接分配的内存,可以通过IDE直接观察到使用情况,也可以使用MAT进行细致的分析。

另一方面,假如我们发现Dalvik Heap没怎么增长,而其他部分增长了许多,这种情况下的分析就要复杂一些。

排除方法通过logcat命令输出的log信息,搜关键词“GC”。如果有下面四个中的一个,就可能存在内存泄露。

GC_FOR_ALLOC:因为在分配内存时内存不够引发的;

GC_EXPLICIT:表明GC被显式请求触发的,如Runtime.gc()或VMRuntime.gc()调用;

GC_CONCURRENT:表明GC在内存使用率达到一定的警戒值时,自动触发;

GC_BEFORE_OOM:表明在抛出内存溢出(OOM)异常之前,尝试执行最后一次内存回收。

二、实战演示(TestMemory.apk实例)

Java堆用于存储对象实例,我们只有不断地创建对象,并且保证GC Roots到对象之间有可达路径来避免垃圾回收机制清除这些对象,就会在对象数量到达最大堆的容量限制后产生内存溢出异常。

图五、六操作导致的内存泄漏部分代码如下:

58e23e02cf6f98fa939e41f84a8cccf7.png

b1dfdb852cf0860e9695688f6c73c2c1.png

在一个MainActivity,实现了listeners。 这个MainActivity中,addMemory.setOnClickListener创建一个大的字符串数组,不断点击此按钮导致内存泄漏;持续点击直到内存溢出。在跳转页面clickToSecondPage.setOnClickListener后,staticActivity 引用MainActivity导致内存泄漏。

分析TestMemory内存泄漏任务包括:

1) 检测泄露的Activity实例

2) 查找重复的String实例

HPROF Viewer界面,分析内存泄漏。如图20:

e8f60b73647a3908ff1a655fa86600cb.png

图20 内存泄漏分析

第一步➡️

点击“Analyzer Tasks”视图中的启动按钮,启动分析。

第二步➡️

查看“Analysis Result”中的分析结果,点击“Leaked Activities”中的具体实例,该实例的引用关系将会展示在“Reference Tree”视图中。

第三步➡️

根据“Reference Tree”视图中的引用关系找到是谁让这个leak的activity活着的,也就是谁支配(Dominate)这个activity对象。

此例中, 比较简单,可以很清晰看到是this的实例最终支配了MainActivity。“this”实例连接到GC Roots,故而导致MainActivity GC Roots可达,无法被回收。

上述步骤, 可以让我们快速定位可能的内存泄露。 当然,内存问题,除了内存泄露,还有内存消耗过大。我们可以在Heap Viewer中查看分析内存的消耗点。

使用Heap Viewer查看内存消耗。如图21:

b9a7dba831b568a84868ff634b87abc6.png

图21 Heap Viewer查看内存消耗

第一步➡️

点击视图中“Package Tree View”的按钮, 使用包视图,可以让我们关注到自动APP相关对象的实例。

第二步➡️

点击“Retained Size”排序, 快速找到内存消耗点。

第三步箭头

找到最大内存消耗点。

总结

分析内存问题, 主要是观察和比较内存增长情况。然后,分析对象的内存占用(Retained Size)情况,找出Retained Size较大的对象,找到其直接支配者(Immediate Dominator),跟踪其GC可达路径(Path to GC Roots),从而找到是谁让这个大对象活着。(🔚)

1e27a8e175acac7608dcdfc3a6464fc4.png

参考资料:

1. 文档,Android内存分析指南,追逐 编写

2. 《深入理解Java虚拟机:JVM高级特性与最佳实践》,周志明 著,机械工业出版社

3. 《移动App性能评测与优化》,TMQ专项测试团队 编著,机械工业出版社

PS:感谢光荣之路的追逐和悟空老师悉心的指导和热情的帮助,让我获益匪浅!

a0c09ac0c4db11f3b751fbcba7865ac3.png

声明:欢迎非商业用途转载,转载请在明显位置标明“作者、出处、本声明及原文链接”,否则保留追究法律责任的权利。返回搜狐,查看更多

责任编辑:

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值