QAPM原有Hprof分析是基于开源项目LeakCanary的shark Andoroid Extension,这里仅有针对安卓内存泄露部分,同时包含了一个极其简陋的内存触顶分析模块,只能根据一定规则获取极少的信息。为了适应更多针对内存触顶的新分析需求:如图片重复,图片超尺寸,字符串重复,对象重复分析与问题引用链聚类等更复杂的Hprof分析,包括获取更多问题信息时,原方案就显得力不从心,因此重构成了唯一的选择。
原生的内存触顶方案的最致命缺陷在于:能够为技术人员提供的信息太少了,老版本的内存触顶所给出的个例中仅有简单的问题条目以及次数罗列,没有更多的信息出现。因此对技术人员来讲,这样的信息太过于"鸡肋",它只能告诉你发生了什么,却不回答为什么,有多严重,在哪里,以及有什么其他的具体信息。
原型方案在早期构建中使用了内存泄漏的shark库,当然也不是一帆风顺的,其中也陆续发现了一些不足之处,具体可以归结为以下几点
而这些劣势都会引导向两个主要的问题:
因此,我们需要一个全新的Hprof分析组件,以支撑起我们的新需求开发,这个组件的架构主要改进并实现如下特点
在具体实现思路上,我们在索引建立上使用了自己的一套体系,并且拥有全新的对象代理。
与shark不同,我们采用了较为激进的Eager Loading,对分析中常见的操作都建立了索引表,保证分析器查找取用数据的速度。这样一来也可以保证在索引建立完成后,所有的读取都是线程安全的,我们可以尽情的利用多核处理器的能力。
在另外一个层面上,根据业务的实际需求,我们针对代理对象的最短引用链获取做了特别的处理。即在分析时就将最短引用链求出,而不必像原有shark那样在用到时再进行计算。且在实际业务中要获取谁的引用链是无法预知的,这就造成了一个碰运气的问题:如果对象在BFS中遍历处于靠后的位置,或者是其根本从gc root不可达,再加之老方案遍历时是通过访问字段,而字段的加载又是极大可能要触发IO的。这样一整套组合拳下来,整个分析体验就会变得尤其糟糕。新Hprof通过牺牲一些内存,换取高速的引用链获取,极大地提高了体验。
改动前:
改动后:
整个分析器通过注解,反射,DI等技术实现动态控制具体分析器在某次分析中的参与,以及不同分析器的参数设置,精确控制分析器的行为。这也使得后续的维护与扩展工作趋于轻量化,对运维同学友好了许多。
在上面的方向指引下我们已经完成了初版以及后续的改良版本,效果良好。
而针对新索引的发掘与探索也是在初版改进了几次后才逐渐萌生重写想法并且最终成型的。在这其中我们经历了如下的历程:
这个阶段我们直接使用了shark的体系,对控制层与应用层各个分析器进行了开发,满足了基本的分析需求。在初步的版本中,由于没有引用链分析的加入以及使用的hprof较为简单,除开启动预热时间,我们没有发现特别突出的性能问题。然而在加入了引用链分析后,甚至在简单hprof中多个分析器并行获取引用链也会消耗大量的时间与内存。
在上一阶段中,我们发现由于引用链的并行获取,造成了时间的大量消耗与内存的飙高。问题在哪呢?
经过分析,我们得出一个结论,由于当时仍然是处于shark的体系之下,其线程不安全的读取让整个支持并行的策略看起来既滑稽又无奈:为多个分析器分配多个hprof对象,并且分别并行构建。这也直接导致了我们很难在进行分析前就将统一的最短引用链求出,当然其代码封装的高度不灵活性也是阻力的来源。
不仅如此,在原有体系下针对对象的全盘统计也是极为痛苦的,通过Profiling我们发现大多数时间都被耗费在了Okio与磁盘的读取交互上,让人无法接受。
诸多不满之下,更换到一个新的索引系统的想法诞生了。
在设计全新索引和代理体系时,我们尽可能将常用的查询通过映射缓存起来,例如类型名到代理类型对象等,此等操作在原有的索引下是实打实的O(n)时间消耗。这使得我们的任何统计操作时间被大大缩短。
并且针对到以后可能出现的复杂分析,我们特地为对象缓存了一个可达表与对应的可达性类型(实例字段,静态字段,JNI Local等)。
同时我们也借助上面的可达表进行对象最短引用链的构建,以一定的内存牺牲来使得引用链获取是无需任何时间的。
初期的测试中,我们都是使用的较为简单的hprof文件,在新索引体系下没有任何内存与时间消耗问题,但在对真实业务hprof分析时发现了高内存占用与高时间消耗。
优点
缺点
为了解决面对实际业务中的hprof建立索引后高内存占用问题,我们做了与内存相关的性能分析,最终确认了是错误的代理体系设计导致了对象的增多,GC压力也随之增加。
意识到这是一个代理对象系统设计的失误时,我们及时调整了实现方式,放弃一个字段分配一个代理对象的方法,改为使用方法指定加载且完全线程安全的按需加载,并且最终实现了时间消耗与内存占用的平衡。
在原有的泄露基础上,我们加入了四个对内存优化具有针对性的分析器:
除开泄露分析器,其他分析器也充分利用上了预加载的最短引用链信息,通过在一组内分析引用链的相似段,找出最普遍的引用链特征,精准定位群体事件的问题所在。
在更多的信息和高效的修复闭环系统下可以大大提高开发人员的效率,避免了开发人员通过各类工具进行人工操作和分析,快速定位问题所在,将更多精力投放在修复问题上。这也进一步减少了人力消耗,让团队效率更进一步。
列表
详细信息
详细信息
列表
详细的个例信息,以及附加的数据
下半部GC引用链
如果可用的图片预览:可放大查看
提单内容
新内存分析 | 旧内存分析 | LeakCanary 2 | |
---|---|---|---|
分析项 | 多样化,根据分析器制订 | 少量分析,根据规则制定 | 仅有泄露 |
分析结果 | 针对不同类型有专门化的详细信息(如图片的尺寸,像素信息等) | 无 | 无 |
便利功能 | 拥有图片预览导出,字符串内容预览等便捷功能 | 无 | 少量 |
虽然目前已经取得了一些成果,但这还远远不够。
如有兴趣或任何疑问,请联系在线客服:QAPM
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。
原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。
如有侵权,请联系 cloudcommunity@tencent.com 删除。