本文内容整理自公众号腾讯Bugly,感谢原作者的分享。

1、问题背景

对于Android应用来说,内存向来是比较重要的性能指标。内存占用过高,会影响应用的流畅度,甚至引发OOM,非常影响用户体验。因此,内存优化也向来是行业内的重点工作项和难点工作项。

手Q在很早之前就开发了很多内存优化技术:

1)自研内存泄露检测系统 LeakInspector天网:

LeakInspector是一套完整内存泄露检测系统:能够自动检测应用内存泄露问题;并提供兜底回收以及自动提单功能;

2)图片引用大图告警:

能够自动检测出业务图片不合理使用:比如解码的图片尺寸大于显示尺寸2倍以上等问题。推动业务进行专项优化;

3)内存触顶监控:

能够检测出内存不足时占用内存较高的业务场景,并定位到相应的页面,推动业务进行优化。

以上这些技术都取得了很好的内存优化效果,但他们的特点是:主要针对明显的内存问题,缺少更深入的内存分析。

因此,手Q内存问题也一直存在,主要表现在以下两方面:

1)手Q的平均内存一直持续增长,版本间增幅较高,手Q一月一个版本,平均每版本增长大概5.3M;

2)用户的OOM率大概0.1%。

这次我们主要从监控和清理两个角度出发,系统化的进一步优化手Q内存: 

1)统一缓存监控:开发实现全面的内存缓存监控系统,能够更细致的监控手Q内存缓存使用情况,及时发现轻度不合理问题,推进优化;

2)内存清理 在监控的基础上,开发实现自动清理机制:一方面统一调度手Q各业务主动清理内存,另一方面,通过深入的技术研究,实现系统内存清理技术。

通过监控和清理相互配合,我们最终实现了优化手Q整体内存,降低OOM率的效果。以下是详细方案。

学习交流:

- 即时通讯开发交流群:320837163[推荐]

- 移动端IM开发入门文章:《新手入门一篇就够:从零开发移动端IM》

(本文同步发布于:http://www.52im.net/thread-1524-1-1.html)

2、相关文章

《腾讯技术分享:Android手Q的线程死锁监控系统技术实践》

《微信团队原创分享:iOS版微信的内存监控系统技术实践》

《微信团队原创分享:Android内存泄漏监控和优化技巧总结》

《QQ音乐团队分享:Android中的图片压缩技术详解(上篇)》

《QQ音乐团队分享:Android中的图片压缩技术详解(下篇)》

《Android版微信安装包“减肥”实战记录》

《iOS版微信安装包“减肥”实战记录》

《微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化》

3、统一缓存监控

统一缓存监控主要包含图片缓存监控和业务对象缓存监控两部分:

1)图片缓存监控主要关注Bitmap的引用,定位图片问题;

2)业务对象缓存监控,主要监控手Q各业务对象缓存,及时发现缓存问题。

3.1图片缓存监控

对于Android应用来说,Bitmap向来是内存的占用大户。在手Q中平均有300+ Bitmap对象。

统计显示:Bitmap引用内存占手Q总内存40%左右:

减少图片占用内存,需要规范图片缓存的使用。前期我们在手Q中封装实现了图片专用多级缓存QQLruChe,并要求各业务必须使用全局图片专用缓存来缓存图片。一方面可以方便调控图片缓存业务,另一方面,通过淘汰以及清理策略,可以有效控制图片缓存大小。但由于手Q业务众多,业务独立开辟图片缓存的情况还是时有发生。因此我们开发了一套图片缓存监控系统,及时检测出图片缓存私藏问题,同时也监控图片的其他不合理使用。

图片缓存监控使用内存快照技术实现,分为终端数据采集和后台数据分析两部分。

流程如下所示:

终端数据采集:客户端实时检测当前可用内存,当可用内存不足时,自动生成内存快照文件,上报到后台。

后台数据分析:在后台,我们实现了一套Hprof文件分析以及Bitmap引用归并技术,批量分析内存快照文件,输出Bitmap引用链并进行归类统计,过滤全局图片专用缓存以及View层引用后,分析出存在图片缓存私藏的业务。

实现图片缓存监控过程中我们主要遇到以下几个难点:

1)内存快照文件大,约300M左右:

内存文件过大会导致上传流量和存储成本比较大,而且上传耗时长。针对这个问题,一方面,我们对大盘用户采样上报,并提供良好的用户交互。另一方面我们深入分析内存快照采集原理,自研miniDump工具,通过native hook技术在生成内存快照时剔除了tyte[]数据,从而使文件体积减少70%;

2)内存快照文件人工分析成本高:

通过MAT人工分析内存快照文件耗时费力,而且分析数量有限,用户上报的内存文件很多,无法定位top问题。针对该问题,我们深入研究MAT插件技术,自研引用链分析以及Bitmap引用归并工具,自动化分析内存快照文件,归类Bitmap图片引用。

通过图片监控系统,我们有效检测出以下几类业务问题:

1)全局图片专用缓存占用空间大,存在优化空间:

bitmap引用链归并发现全局图片专用缓存占较高。同时,我们也统计了OOM用户全局图片缓存的内存量,平均约10M左右。因此有必要在内存不足时,自动trimToSize,释放内存空间;

2)业务bug——逻辑完成后,没有及时释放图片引用:

业务逻辑存在问题,比如有几类业务在页面退出后,没有及时释放背景图资源引用;

3)业务私自开辟图片缓存:

业务独立开辟缓存cache缓存bitmap,没有使用全局图片专用缓存;

4)业务缓存数据对象中引用图片:

业务内存缓存的数据对象中,含有bitmap成员,内存空间大。可优化为缓存key,bitmap对象存到全局图片专用缓存中;

5)图片静态引用:

定义静态的Bitmap或者Drawable对象,进程周期内,对象所引用的资源都无法释放。

在手Q730版本,图片缓存监控系统检测出32例业务问题,提单26例,累计节省内存约23M。

3.2业务对象缓存监控

业务对象缓存监控主要是通过实现自定义集合类,实时上报各业务内存缓存使用情况到后台。在后台分析归并,从而定位业务缓存问题。

如上图所示,业务对象缓存主要分为终端数据采集、后台数据分析、缓存清理三部分:

终端数据采集: 通过自定义实现QQHashMap,QQConCurrentHashMap,QQLruCache等集合类,在系统原有集合类基础上,封装统计功能,实时统计程序运行期间各缓存的内存指标:插入次数,查询次数,删除次数,遍历次数,命中次数,未命中次数,缓存使用率,内存占用等;

后台分析:分析终端上报的用户数据,对各业务缓存进行归类统计,统计出平均内存占用,最大内存占用,内存占用中位数,缓存命中率,缓存浪费率等指标;

内存清理:监控系统在监控的基础上,也增加了清理接口。当检测到当前可用堆内存比较低,用户处于内存高负荷状态时,统一调度清理逻辑,进行内存自清理优化。

通过统一缓存监控,我们检测出了很多业务缓存问题,主要可归为以下三类。

1)缓存浪费率高:

典型案例1:手Q表情某类缓存,平均浪费率超过88%,相当于缓存1000个对象,有800+没有使用过;

典型案例2:某红包模板缓存,存储后从不访问,浪费率100%。

针对这类问题,推动业务优化内存缓存结构,去除无用缓存,优化缓存方案,以降低浪费率。

2)缓存内存占用大:

典型案例1:手Q某新闻类图片缓存,私自缓存Bitmap,最大占用内存15M,占所有图片缓存的35%;

典型案例2:钱包类背景图缓存,内存占用约1M左右,使用后未及时释放。

针对这类问题,对于缓存图片的业务,推动业务接入全局图片专用缓存;对于非图片类业务,接入自动清理,及时释放内存空间。

3)缓存结构存在优化空间:

典型案例1:讨论组成员缓存,设计为LRUCache可淘汰缓存,但是用户未曾用满过。初始开辟空间过大;

典型案例2:未读消息缓存,极端用户缓存个数超过9000个,无数量上限控制。

针对这类问题,推动业务更新或者优化缓存结构,增加上限控制等。

4、内存清理

统一监控,可以有效发现业务缓存问题进行专项优化。但监控具有一定的滞后性,因此在监控的基础上,我们同时也增加了内存清理控制模块。

内存清理主要分为业务内存清理以及系统内存清理。业务内存清理,包含统一图片缓存清理,以及业务缓存对象清理两部分。这里前文已简单介绍。接下来我们介绍下两例系统相关的内存清理技术:系统ClassLoader内存清理和系统预加载图片清理。

4.1系统ClassLoader内存清理

前期,我们分析了很多内存快照,发现一个共性的问题:在内存快照中有个ZipFile对象,内存占用一直超过2.6M。这个zipFile被系统类ClassLoader引用。

通过分析系统源码,我们发现ZipFile记录了安装包所有的类文件信息,手Q安装包中有超过15000个文件,文件越多,zipFile占用内存就越大。

我们进一步分析ClassLoader相关源码,发现只有在调用ClassLoader的findResource方法查找图片等安装包内资源时,才会使用到ZipFile的内容,未发现其他使用场景。同时,通过findResource方式查找资源存在一定的弊端:耗时很长,在Android系统上不推荐使用。

详情分析可参考:

http://blog.nimbledroid.com/2016/04/06/slow-ClassLoader.getResourceAsStream-zh.html

综合评估,可以清理ClassLoader引用的这块内存。

清理主要面临以下几个难点:

1)Android系统碎片化严重,兼容性问题比较突出:

不同版本,zipFIle成员变量的位置以及变量名不同。zipFile初始化时机改变:4.3以前创建时即初始化,4.3之后,第一次访问才会初始化。各厂商对系统API内部修改无法预期;

2)强行清理,可能导致功能异常:

系统内部代码逻辑可能会受到影响,而且影响无法预期。手Q当前使用ClassLoader查找资源的业务功能会受到影响。后期新增业务无法预期,清理会导致系统功能失效;

3)清理后再次加载zipFile耗时长,可能导致卡顿。

下图是我们清理系统ClassLoader的实现方案,采用代理,兜底,缓存,上报等手段逐一攻克以上难点,完美实现清理系统ClassLoader内存的效果。

1)针对兼容性问题,我们通过反射代理替换了系统的ZipFile为HookZipFile,替换完成后,清理掉zipFile内存。替换机制兼容系统不同版本以及特殊机型,对系统逻辑无影响。

2)针对清理导致的功能异常,我们实现了兜底能力,下次访问时,会重新创建zipFile。

3)针对耗时问题,内部封装实现缓存功能。并针对业务访问增加堆栈上报,及时推动业务改用其他方式获取资源。

内存清理方案,通过内部兼容性测试,发布后外网无crash问题,通过不断迭代,兼容率达到100%。并且内存清理效果明显,平均清理内存量约2.6M。

4.2系统预加载图片清理

系统预加载图片缓存是zygote进程初始化时,通过preloadResources()预加载的通用图片资源,后续android应用进程都是从Zygote fork出来的,所以就继承了这部分预加载的图片资源。由于是静态强引用,这部分图片资源会一直占用内存空间。

预加载的好处在于系统只在zygote执行一次加载操作,所有应用用到该资源不需要再重新加载,减少资源加载耗时。与此同时,sPreloadedDrawables属于静态对象,会一直引用图片缓存,所以该系统机制会占用较高内存,在有些系统上,内存占用空间超过20M。

因此这里存在内存优化的空间,当内存占用高时,可以主动清理掉这部分内存,以便释放可观的堆内存空间,减少内存耗尽的风险。通过分析drawable加载机制的源码,我们了解到如果预加载的资源没有在sPreloadedDrawables中找到,会重新decode解码加载,不会影响现有功能。

因此清理后的风险可控,主要面临的难点是兼容性问题:

1)系统API变动较多:

sPreloadDrawables数据结构类型,对象存储位置,不同API版本之间都有改动;

2)厂商自定义修改较多:

比如:小米7.0系统以及华为部分机型各自扩展了ResourceImpl实现,自定义了自己的资源加载基类,导致无法定位到sPreloadDrawable;OPPO部分机型,修改了sPreloadDrawable类的属性等等。

下图是我们清理系统预加载图片缓存的实现方案,通过反射替换的方式,拦截替换系统的预加载缓存为自定义图片缓存,内部管理图片加载,在内存不足时,及时清理预加载图片缓存。

针对兼容性问题,我们实现了一套完备的兼容性方案:

1)替换前兼容检测;

2)系统版本兼容处理;

3)特定机型兼容处理;

4)失败上报统计,不断兼容。

系统预加载图片清理,通过不断迭代,已经可以兼容几乎所有机型。版本发布后,未引入系统功能异常以及外网crash问题。内存清理量比较可观:平均在15M左右,最高达到25M。

5、优化后的效果

5.1横向对比

在灰度阶段,我们对用户进行了ABTest测试,一半用户接入内存优化逻辑,一半用户不接入。大盘上报统计显示:优化用户OOM率明显低于未优化用户:OOM率由0.09%降至0.053%。

内存分布方面,内存优化显著降低了高内存用户占比。由3.05%降至1.7%。高内存用户是指当前可用内存不足20%的用户,是OOM高发用户群,降低这部分用户比例,可有效降低OOM率。

5.2纵向对比

我们从7.3.0版本接入内存优化,从版本迭代来看,优化效果显著:OOM率由0.09%左右降低至0.047%左右,降幅47%:

手Q版本间平均内存增幅明显放缓,版本增幅由5.8M左右降至1.14M左右:

附录:更多微信、QQ的文章汇总

[1] QQ、微信团队原创技术文章:

《腾讯技术分享:Android版手机QQ的缓存监控与优化实践》

《微信团队分享:iOS版微信的高性能通用key-value组件技术实践》

《微信团队分享:iOS版微信是如何防止特殊字符导致的炸群、APP崩溃的?》

《让互联网更快:新一代QUIC协议在腾讯的技术实践分享》

《iOS后台唤醒实战:微信收款到账语音提醒技术总结》

《腾讯技术分享:社交网络图片的带宽压缩技术演进之路》

《微信团队分享:视频图像的超分辨率技术原理和应用场景》

《微信团队分享:微信每日亿次实时音视频聊天背后的技术解密》

《腾讯团队分享:手机QQ中的人脸识别酷炫动画效果实现详解》

《腾讯团队分享 :一次手Q聊天界面中图片显示bug的追踪过程分享》

《微信团队分享:微信Android版小视频编码填过的那些坑》

《微信手机端的本地数据全文检索优化之路》

《企业微信客户端中组织架构数据的同步更新方案优化实战》

《微信团队披露:微信界面卡死超级bug“15。。。。”的来龙去脉》

《QQ 18年:解密8亿月活的QQ后台服务接口隔离技术》

《月活8.89亿的超级IM微信是如何进行Android端兼容测试的》

《以手机QQ为例探讨移动端IM中的“轻应用”》

《一篇文章get微信开源移动端数据库组件WCDB的一切!》

《微信客户端团队负责人技术访谈:如何着手客户端性能监控和优化》

《微信后台基于时间序的海量数据冷热分级架构设计实践》

《微信团队原创分享:Android版微信的臃肿之困与模块化实践之路》

《微信后台团队:微信后台异步消息队列的优化升级实践分享》

《微信团队原创分享:微信客户端SQLite数据库损坏修复实践》

《腾讯原创分享(一):如何大幅提升移动网络下手机QQ的图片传输速度和成功率》

《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(下篇)》

《腾讯原创分享(二):如何大幅压缩移动网络下APP的流量消耗(上篇)》

《微信Mars:微信内部正在使用的网络层封装库,即将开源》

《如约而至:微信自用的移动端IM网络层跨平台组件库Mars已正式开源》

《开源libco库:单机千万连接、支撑微信8亿用户的后台框架基石 [源码下载]》

《微信新一代通信安全解决方案:基于TLS1.3的MMTLS详解》

《微信团队原创分享:Android版微信后台保活实战分享(进程保活篇)》

《微信团队原创分享:Android版微信后台保活实战分享(网络保活篇)》

《Android版微信从300KB到30MB的技术演进(PPT讲稿) [附件下载]》

《微信团队原创分享:Android版微信从300KB到30MB的技术演进》

《微信技术总监谈架构:微信之道——大道至简(演讲全文)》

《微信技术总监谈架构:微信之道——大道至简(PPT讲稿) [附件下载]》

《如何解读《微信技术总监谈架构:微信之道——大道至简》》

《微信海量用户背后的后台系统存储架构(视频+PPT) [附件下载]》

《微信异步化改造实践:8亿月活、单机千万连接背后的后台解决方案》

《微信朋友圈海量技术之道PPT [附件下载]》

《微信对网络影响的技术试验及分析(论文全文)》

《一份微信后台技术架构的总结性笔记》

《架构之道:3个程序员成就微信朋友圈日均10亿发布量[有视频]》

《快速裂变:见证微信强大后台架构从0到1的演进历程(一)》

《快速裂变:见证微信强大后台架构从0到1的演进历程(二)》

《全面总结iOS版微信升级iOS9遇到的各种“坑”》

《微信团队原创资源混淆工具:让你的APK立减1M》

《微信团队原创Android资源混淆工具:AndResGuard [有源码]》

《移动端IM实践:iOS版微信界面卡顿监测方案》

《微信“红包照片”背后的技术难题》

《移动端IM实践:iOS版微信小视频功能技术方案实录》

《移动端IM实践:Android版微信如何大幅提升交互性能(一)》

《移动端IM实践:Android版微信如何大幅提升交互性能(二)》

《移动端IM实践:实现Android版微信的智能心跳机制》

《移动端IM实践:WhatsApp、Line、微信的心跳策略分析》

《移动端IM实践:谷歌消息推送服务(GCM)研究(来自微信)》

《移动端IM实践:iOS版微信的多设备字体适配方案探讨》

《信鸽团队原创:一起走过 iOS10 上消息推送(APNS)的坑》

《腾讯信鸽技术分享:百亿级实时消息推送的实战经验》

>> 更多同类文章 ……

[2] 有关QQ、微信的技术故事:

《技术往事:微信估值已超5千亿,雷军曾有机会收编张小龙及其Foxmail》

《QQ和微信凶猛成长的背后:腾讯网络基础架构的这些年》

《闲话即时通讯:腾讯的成长史本质就是一部QQ成长史》

《2017微信数据报告:日活跃用户达9亿、日发消息380亿条》

《腾讯开发微信花了多少钱?技术难度真这么大?难在哪?》

《技术往事:创业初期的腾讯——16年前的冬天,谁动了马化腾的代码》

《技术往事:史上最全QQ图标变迁过程,追寻IM巨人的演进历史》

《技术往事:“QQ群”和“微信红包”是怎么来的?》

《开发往事:深度讲述2010到2015,微信一路风雨的背后》

《开发往事:微信千年不变的那张闪屏图片的由来》

《开发往事:记录微信3.0版背后的故事(距微信1.0发布9个月时)》

《一个微信实习生自述:我眼中的微信开发团队》

《首次揭秘:QQ实时视频聊天背后的神秘组织》

>> 更多同类文章 ……

(本文同步发布于:http://www.52im.net/thread-1524-1-1.html)

转载于:https://www.cnblogs.com/jb2011/p/8743044.html

腾讯技术分享:Android版手机QQ的缓存监控与优化实践相关推荐

  1. android QQ动态tab,变化忒大了!Android版手机QQ 5.0体验

    变化忒大了!Android版手机QQ 5.0体验 出处:快科技 2014-07-28 12:02:56     作者:随心 编辑:随心[爆料] 收藏文章 内容导航: 第[01]页:[Android版手 ...

  2. android版手机qq 5.0,手机QQ5.0安卓版今日正式发布 手机QQ5.0更新升级内容介绍

    今日,手机QQ5.0安卓版正式发布,相较之前的版本,这个版本对整体界面结构和视觉风格做了重大调整,变得更加简洁,聚焦社交沟通.下面就详情一起来看看了解一下吧 手机QQ 5.0采用蓝色主界面,个人头像从 ...

  3. android版手机qq退出方法,安卓qq2013怎么退出 手机qq4.1怎么退出方法

    现在qq越升级用户体验越差劲,前段时间iphone版qq升级到4.0后骂声不断,而安卓qq4.1也不例外,升级后都不知道怎么退出qq,这里就来为大家说说安卓QQ4.1怎么退出. 像以前的版本我们可以直 ...

  4. 腾讯技术分享:微信小程序音视频技术背后的故事

    1.引言 微信小程序自2017年1月9日正式对外公布以来,越来越受到关注和重视,小程序上的各种技术体验也越来越丰富.而音视频作为高速移动网络时代下增长最快的应用形式之一,在微信小程序中也当然不能错过. ...

  5. 腾讯技术分享:腾讯是如何大幅降低带宽和网络流量的(图片压缩篇)

    1.前言 每年年初腾讯公司都要制定 SNG 成本优化年度目标,过去三年已经用技术手段为公司节省了超过 10 亿的现金流.产品的架构和容量也越来越健康,继续成本优化变得十分艰难. 但我们在迷茫中仍然定下 ...

  6. 微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)

    1.点评 对于IM系统来说,如何做到IM聊天消息离线差异拉取(差异拉取是为了节省流量).消息多端同步.消息顺序保证等,是典型的IM技术难点. 就像即时通讯网整理的以下IM开发干货系列一样: <I ...

  7. 微信技术分享:微信的海量IM聊天消息序列号生成实践(容灾方案篇)

    1.引言 在本文的上篇<微信技术分享:微信的海量IM聊天消息序列号生成实践(算法原理篇)>中介绍了微信的消息序列号生成器 seqsvr 的算法原理.架构核心思想,以及 seqsvr 随着业 ...

  8. Android 模仿手机QQ表情输入和表情预览框

    闲来无事花了一点空暇时间写了一个模仿Android版手机QQ的表情输入框 效果图如下 实现步骤 一:布局 二:录入填充表情 三:监听表情的适配器的触摸监听显示出预览框 一 .布局 我是自己自定一个Ex ...

  9. java 浏览器 qq_qq浏览器通用版 手机QQ浏览器v2.1Java通用版下载

    qq浏览器通用版 手机QQ浏览器v2.1Java通用版下载 手机QQ浏览器v2.1通用版 软件类型: 手机浏览器 适用手机: java 软件大小: 591 KB 更新日期: 2011-06-12 浏览 ...

  10. Android仿手机QQ空间动态评论,自动定位到输入框

    手机QQ空间浏览好友动态时,可以直接对动态评论,点击某条评论,动态列表自动滚动,使输入框刚好在该评论下面,而不会覆盖住评论内容.如下图所示, 首先要实现输入框刚好在输入面板上面,且动态列表不会被挤上去 ...

最新文章

  1. vue里面嵌入sound music音乐播放
  2. linux 线程 pthread create 源码 剖析
  3. cordova开发插件,并在android studio中开发、调试
  4. 计算机之间是如何实现通信的?—Vecloud微云
  5. (转)K-近邻算法(KNN)
  6. Django从理论到实战(part12)--应用命名空间和实例命名空间
  7. 是vans_硬核复刻,就服VANS棋盘格
  8. android软件perthbus,Transit
  9. 网页设计个人主页源码_WebSSH - 网页上的SSH终端
  10. 移动测试之-流量测试方案
  11. TDtree冲刺第四天
  12. 8.业务架构·应用架构·数据架构实战 --- 技术方案书
  13. 单片机 | Keli 调试程序
  14. 电视剧《都挺好》弹幕数据分析
  15. OIer__ZLY__OI计划
  16. bootstrap组件——导航条
  17. 初识Espresso
  18. Android工程师进阶第五课 多线程锁,线程池和DVM/ART优化
  19. 大数据分析原地踏步 原来是分析工具面临信任问题
  20. 计算机控制作业来看,带PID控制器的最小拍系统设计

热门文章

  1. 《为学》 [清]彭端淑
  2. sort排序和uniq使用
  3. Jenkins 持续集成平台构建之通过git提交代码
  4. rsync使用(二)
  5. java容器取交集、并集、补集、差集示例
  6. 华为 EC169 3G上网卡在MacPro中的使用
  7. 如何删除档案中的重复的行
  8. Flex布局新旧混合写法详解(兼容微信)
  9. 2步轻松搞定SpringBoot2.x分布式session共享,极少配置
  10. 企业API接口设计之token、timestamp、sign具体实现