【腾讯优测干货分享】如何降低App的待机内存(三)——探索内存增长的原因
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/8BiKIt3frq9Yv9KV5FXlGw
1.3新问题的进一步挖掘
在上一节里,我们介绍了内存测试的基本流程,讲述了如何发现并处理简单的内存问题。对于Dalvik Heap部分总结出了一些常见的问题模式,以及如何使用工具识别和处理这些常见的内存问题。
当简单问题不再是问题的时候,我们就会开始遇上一些奇怪问题了,类似于下面这些:
“我们这个版本引入了一个挺简单的库,内存就涨了2M”
“这些代码只是初始化了几个对象,还没有开始用呢”
“我只是改了一行代码,没有创建新对象”
“我一行代码都没改,怎么会涨呢”
这次出现的问题就是这样这一类问题,新版本的Dalvik Heap Pss内存出现了2M左右的增长。但Dalvik Heap Alloc只增长了273K的情况下。而从Dalvik Heap Free也能看出大部分增长的内存是空闲状态的。
经过一段时间对问题的观察,我们有以下几点发现:
- 经过较长时间待机后也没有被释放回系统。
- 有几处代码会导致内存增长,只要将这些代码屏蔽掉,内存情况就下降到正常水品。
- 这些代码分配的内存并不多,甚至有些地方是不需要分配内存的。
- 有些代码并不是这个版本新加入的,已经存在较长时间了。
- 使用裁剪功能的方法编译并分析内存后,基本可以确定是新加入代码消耗了内存,但并没有内存泄漏,代码经过review也没有发现问题。
这个结果让我们陷入了困惑,常用的方法找不出问题,说明有更深层次的原因。接下来要从更底层的Dalvik虚拟机寻找问题。
1.3.1 Dalvik Heap内部机制
为了弄清楚为什么DVM占着内存不释放,我们阅读了DVM分配内存部分的代码。位置在Android源码的dalvik/vm/alloc下,约255K。分析出的主要流程如下:
1) DVM使用mmap系统调用从系统分配大块内存作为Java Heap。根据系统机制,如果分类的内存尚未真正使用,就不计入PrivateDirty和PSS。例如图1-8,Heap Size/Alloc很多,但大部分是共享,实际使用的较少。所以反映到PrivateDirty/PSS里的内存并不多。

图1-8 共享内存较多的进程
2) New对象之后,由于要向对应的地址写入数据,内核开始真正分配该地址对应的4K物理内存页面。
Alloc.cpp, 176行起:

图1-9 DVM虚拟机分配内存的代码
3) 运行一段时间后,开始GC,有些对象被回收了,有些会一直存在,如图1-10所示。

图1-10黑点表示的内存会被回收
4) 在GC时,有可能会进行trim。即将空闲的物理页面释放回系统,表现为PrivateDirty/PSS下降。
HeapSource.cpp, 431行:

图1-11 释放内存回系统的代码(一)
HeapSource.cpp,1304行:

图1-12 释放内存回系统的代码(二)
1.3.2 问题所在
在了解DVM分配释放内存的机制后,根据dumpsys观察到的现象,猜测可能出现了页利用率问题(页内碎片)。如图1-13所示,第一行:在开始阶段,内存分配的较满。第二行:经过GC后,大部分对象被释放,少部分留下来。

图1-13产生内存碎片
这种情况下可能会产生的问题是,整页的4K内存中可能只有一个小对象,但统计PrivateDirty/PSS时还是按4K计算。
在通常的jvm虚拟机中,有Compacting GC机制,整理内存对象,将散布的内存移动到一起。但根据DVM的代码,DVM的Mark-Sweep算法不能移动对象,即没有内存整理功能,这种情况下就会形成内存空洞。
在猜测了可能的问题后,需要验证是否如猜测原因所致,由于MAT的对象实例数据中有地址和大小信息,我们先从MAT中导出数据。
在MAT中列出所有对象实例:list_objects java.*,然后选中所有数据导出为CSV格式,如下所示:
Class Name,Shallow Heap,Retained Heap,
class java.lang.Class @ 0x41fdd1e8,16,56,
class test.bxi$3 @ 0x432501c8,0,0,
class test.aaw$c$1 @ 0x4324fef8,0,0,
class test.ds @ 0x4324fc88,8,48,
class test.bxh @ 0x4324f438,8,248,
class test.bxg @ 0x4324f248,0,0,
class test.bxd$1 @ 0x4324f028,0,0,
处理导出的csv文件,按页面进行统计,取每个对象的地址的高位(&0xfffff000),结果相同的对象处在同一页面中。最后再按每个页面所有对象的大小分类统计,做出直方图如图1-14所示。

图1-14对页面利用率进行分类统计
这张图就是被测应用的页面利用率分布图,左边是利用率低的页面,右边是利用率高的页面。如果发现利用率低的页面数目增加,说明小对象碎片的数量增加了。
1.3.3 优化Dalvik内存碎片
为了能够找出有问题的代码,我们将上一步得到的数据继续处理。取出所有使用不满2K的页面的内存块地址,再使用OQL将地址导入到MAT中,分析地址对应的对象是什么。如图1-15所示就是将地址重新导入到MAT中得到的对象列表了:

图1-15内存碎片页中的对象
在这里基本就能看出来是哪些对象造成了内存的碎片化,数量比较多的前几个类的自然嫌疑比较大,可以先对前几个类的相关代码进行分析。也可以对这些代码进行针对性的内存测试,观察内存情况。
通过对生成这些对象的代码分析和模拟实验,我们还原出问题的基本过程:
- 生成对象过程需要较多的临时变量。
- 批量生成过程中,由于还有空闲内存,虚拟机没有做GC。
- 完成后才进行GC,清除了所有的零时变量,留下碎片化的内存。
下图是造成这个问题的类似代码,执行这段代码将会在内存中形成很多碎片,造成很高的PSS占用。
private Object result[] = new Object[100];
void foo() {
for(int i = 0; i < 100; ++i) {
byte[] tmp = new byte[2000];
result[i] = new byte[4];
}
}
图1-16显示了类似情况下数组的分配范围,可见数组中每个成员的内存地址都是不连续的,并且相隔很远。这种情况下就会消耗很多个物理内存页面,增加Heap Free,造成例子中的问题。

图1-16内存碎片对象地址的例子
经验小结
根据上述的流程,我们搞清楚了造成问题的原因,并且找到了问题代码。那么应当总结一些经验,以供借鉴。对于测试人员来说,有以下两个经验:
- MAT是探索Java堆并发现问题的好帮手,能够迅速发现常见的图片和大数组等问题。但仅靠MAT提供的功能也不是万能的,比如这个问题的数据就隐藏在对象的地址中。
- 对Android测试经验来说,可能容易找到的是应用代码及框架的各种测试经验和指导,底层以及涉及性能的测试经验并不太多。这方面可以借鉴Linux系统的测试经验,了解内核及进程相关的知识,熟悉常用工具。
- 内存分配的最小单位是页面,通常为4K。
对于开发人员,以下两个经验也许能有帮助:
- 尽量不要在循环中创建很多临时变量。
- 可以将大型的循环拆散,分段或者按需执行。
更多精彩内容欢迎关注腾讯优测的微信公众账号:

腾讯优测是专业的移动云测试平台,为应用、游戏、H5混合应用的研发团队提供产品质量检测与问题解决服务。不仅在线上平台提供app自动化测试、云真机远程操控与调试、私有自动化测试工具XTest等多种质量检测工具,更为VIP客户配备了专家团队提供定制化综合测试解决方案。
【腾讯优测干货分享】如何降低App的待机内存(三)——探索内存增长的原因的更多相关文章
- 【腾讯优测干货分享】如何降低App的待机内存(四)——进阶:内存原理
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/3FTPFvZRqyAQnU047kmWJQ 1.4进阶:内存原理 在 ...
- 【腾讯优测干货分享】如何降低App的待机内存(二)——规范测试流程及常见问题
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:https://mp.weixin.qq.com/s/806TiugiSJvFI7fH6eVA5w 作者:腾讯TMQ专项测 ...
- 【腾讯优测干货分享】越用越卡为哪般——如何降低App的待机内存(一)
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/1_FKMbi1enpcKMqto-o_FQ 作者:腾讯TMQ专项测试 ...
- 【腾讯优测干货分享】如何降低App的待机内存(五)——优化dex相关内存及本章总结
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/01Abwe0p1h3WLh28Tzg_Dw 1.5案例:优化dex相 ...
- 【腾讯优测干货分享】安卓专项测试之GPU测试探索
本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57c7ffdc0569a1191bce8a63 作者:章未哲——腾讯SNG质 ...
- 【腾讯优测干货分享】Android 相机预览方向及其适配探索
本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/583ba1df25d735cd2797004d 由于Android系统的开放策略 ...
- 【腾讯优测干货分享】微信小程序之自动化亲密接触
本文来自于腾讯优测公众号(wxutest),未经作者同意,请勿转载,原文地址:http://mp.weixin.qq.com/s/HcPakz5CV1SHnu-U8n85pw 导语 山雨欲来风满楼,最 ...
- 【腾讯优测干货分享】Android内存泄漏的简单检查与分析方法
本文来自于Dev Club 开发者社区,非经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/57d14047603a5bf1242ad01b 导语 内存泄漏问题大约是An ...
- 【腾讯优测干货】看腾讯的技术大牛如何将Crash率从2.2%降至0.2%?
小优有话说: App Crash就像地雷. 你怕它,想当它不存在.无异于让你的用户去探雷,一旦引爆,用户就没了. 你鼓起勇气去扫雷,它却神龙见首不见尾. 你告诫自己一定开发过程中减少crash,少埋点 ...
随机推荐
- ASP.NET Core 中文文档 第四章 MVC(3.8)视图中的依赖注入
原文:Dependency injection into views 作者:Steve Smith 翻译:姚阿勇(Dr.Yao) 校对:孟帅洋(书缘) ASP.NET Core 支持在视图中使用 依赖 ...
- 【SQLServer】【恢复挂起的解决方案】附加文件时候的提示“无法重新生成日志,原因是数据库关闭时存在打开的事务/用户,该数据库没有检查点或者该数据库是只读的。 ”【数据库恢复】
汇总篇:http://www.cnblogs.com/dunitian/p/4822808.html#tsql 先贴错误: 吐槽一下: 进入正题: 新建一个同名数据库 停止MSSQL服务 替换数据库文 ...
- .NET平台开源项目速览(16)C#写PDF文件类库PDF File Writer介绍
1年前,我在文章:这些.NET开源项目你知道吗?.NET平台开源文档与报表处理组件集合(三)中(第9个项目),给大家推荐了一个开源免费的PDF读写组件 PDFSharp,PDFSharp我2年前就看过 ...
- 谈谈一些有趣的CSS题目(十)-- 结构性伪类选择器
开本系列,谈谈一些有趣的 CSS 题目,题目类型天马行空,想到什么说什么,不仅为了拓宽一下解决问题的思路,更涉及一些容易忽视的 CSS 细节. 解题不考虑兼容性,题目天马行空,想到什么说什么,如果解题 ...
- 【原创分享·微信支付】C# MVC 微信支付教程系列之现金红包
微信支付教程系列之现金红包 最近最弄这个微信支付的功能,然后扫码.公众号支付,这些都做了,闲着无聊,就看了看微信支付的其他功能,发现还有一个叫“现金红包”的玩意,想 ...
- jQuery.Ajax IE8 无效(CORS)
今天在开发的时候,遇到一个问题,$.get()在 IE8 浏览器不起作用,但 Chrome,Firefox 却是可以的,网上资料很多,最后发现是 IE8 默认不支持 CORS 请求,需要手动开启下: ...
- DDD 领域驱动设计-两个实体的碰撞火花
上一篇:<DDD 领域驱动设计-领域模型中的用户设计?> 开源地址:https://github.com/yuezhongxin/CNBlogs.Apply.Sample(代码已更新) 在 ...
- AI人工智能系列随笔
初探 AI人工智能系列随笔:syntaxnet 初探(1)
- 深入理解DOM节点操作
× 目录 [1]创建节点 [2]插入节点 [3]移除节点[4]替换节点[5]复制节点 前面的话 一般地,提起操作会想到“增删改查”这四个字,而DOM节点操作也类似地对应于此,接下来将详细介绍DOM的节 ...
- 满堂红CIO邓劲翔:房屋中介突围
人脸识别.客户关系管理进度监控.业务流程实时监控.网站访问人数及流量实时监控等实际企业应用场景淋漓尽致.羽羽如生的以大屏幕上图表形式展现在人们面前,如果你不去继续询问,你不会知道这是一家才刚刚在房地产 ...