前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >技术揭秘,QAPM的这位Android内存分析“专家”

技术揭秘,QAPM的这位Android内存分析“专家”

原创
作者头像
010101011001
修改2021-02-09 15:32:46
1.1K0
修改2021-02-09 15:32:46
举报

祝大家新春快乐,技术干货来袭。不知道各位还记得许久之前分享过的Finder吗?记得我们在QQ的零人力内存测试的实践吗?之前的那个专家叫“Finder”,基于MAT改造,造就了许许多多的新功能,不过已经有点老了,LeakCanary都出2了,而且还用kottin重写,性能和功能都有了质的飞跃。对于有技术追求的我们,怎敢落后,至此,这位的内存分析专家已经融入到了我们的分析云之中。下面从技术角度我们来揭开这位技术专家的秘密。

背景,追赶QAPM的愿景

QAPM原有Android内存快照分析是基于那个颇具历史感的MAT的命令行版本开发的。MAT到现在都依旧是最最强大的内存快照分析工具,就是他那个类SQL的查询能力灵活性就已经甩很多工具N条街。但是我们是个基于大数据的监控平台,我们用大数据来帮助研发聚焦问题根因的愿景,MAT的数据处理性能明显赶不上我们。后面我们发现了开源项目LeakCanary的Shark Android Extension更新,虽然功能有点简单,能处理部分安卓内存泄露,很简单内存触顶分析模块,但是用kottin重写,传说性能是以前的3倍。为了让技术赶上我们的愿景,我们切换到了Shark。下面我们从两个维度来说说,我们基于Shark如何进一步地性能优化,功能上,我们对其进行强化,加入图片重复,图片超尺寸,字符串重复,对象重复分析与问题引用链聚类等更复杂的Hprof分析。

也许是基于Shark从代码层面的终极性能优化

- 分析源码问题

我们在分析Shark的源码的时候,发现了下面一些可以优化的问题,

  • 原生的堆对象代理体系索引较少,大部分操作使用Lazy Loading甚至为顺序查找,对一些要进行局部统计的操作极端不友好,耗时相对很长。
  • 不保证读取线程安全,多个分析无法在一个索引上同时进行。
  • 使用Okio + Position实现Lazy Loading,需要与IO进行交互,甚至在读取时都要创建一票对象,对GC造成压力,分析速度大大降低。
  • 对象代理体系封装死板,类型系统不够简洁,没有从外部穿透的灵活性,进行复杂业务分析困难,改写也较为困难。

根据这些问题,我们的优化目标聚焦下下面三点,

  • 大部分对象查找时间复杂度为O(1)
  • 建立索引后必须保证无锁的并发
  • 更简洁,高效,且优雅易用的代理对象体系

- 性能优化: Eager Loading

在具体实现思路上,我们在索引建立上使用了自己的一套体系,并且拥有全新的对象代理。

与shark不同,我们采用了较为激进的Eager Loading,对分析中常见的操作都建立了索引表,保证分析器查找取用数据的速度。这样一来也可以保证在索引建立完成后,所有的读取都是线程安全的,我们可以尽情的利用多核处理器的能力。

在另外一个层面上,根据业务的实际需求,我们针对代理对象的最短引用链获取做了特别的处理。即在分析时就将最短引用链求出,而不必像原有shark那样在用到时再进行计算。且在实际业务中要获取谁的引用链是无法预知的,这就造成了一个碰运气的问题:如果对象在BFS中遍历处于靠后的位置,或者是其根本从gc root不可达,再加之老方案遍历时是通过访问字段,而字段的加载又是极大可能要触发IO的。这样一整套组合拳下来,整个分析体验就会变得尤其糟糕。新Hprof通过牺牲一些内存,换取高速的引用链获取,极大地提高了体验。

优化前:

优化后:

- 性能优化:新索引系统

在初步的版本中,由于没有引用链分析的加入以及使用的hprof较为简单,除开启动预热时间,我们没有发现特别突出的性能问题。然而在加入了引用链分析后,甚至在简单hprof中多个分析器并行获取引用链也会消耗大量的时间与内存。

发现问题

在上一阶段中,我们发现由于引用链的并行获取,造成了时间的大量消耗与内存的飙高。问题在哪呢?

经过分析,我们得出一个结论,由于当时仍然是处于shark的体系之下,其线程不安全的读取让整个支持并行的策略看起来既滑稽又无奈:为多个分析器分配多个hprof对象,并且分别并行构建。这也直接导致了我们很难在进行分析前就将统一的最短引用链求出,当然其代码封装的高度不灵活性也是阻力的来源。

不仅如此,在原有体系下针对对象的全盘统计也是极为痛苦的,通过Profiling我们发现大多数时间都被耗费在了Okio与磁盘的读取交互上,让人无法接受。诸多不满之下,更换到一个新的索引系统的想法诞生了。

解决问题

在设计全新索引和代理体系时,我们尽可能将常用的查询通过映射缓存起来,例如类型名到代理类型对象等,此等操作在原有的索引下是实打实的O(n)时间消耗。这使得我们的任何统计操作时间被大大缩短。

并且针对到以后可能出现的复杂分析,我们特地为对象缓存了一个可达表与对应的可达性类型(实例字段,静态字段,JNI Local等)。

同时我们也借助上面的可达表进行对象最短引用链的构建,以一定的内存牺牲来使得引用链获取是无需任何时间的。

优化成果

功能强化,从内存分析小白到内存分析专家

在Android系统中,Java的语境下,那些内存分析小白就只是知道Activity内存泄漏,外网也有一堆这样的文章。Shark的核心分析能力,针对的也是Activity内存泄漏。好,我先来端正下概念。

Java没有真正意义上的“内存泄漏” = Memory Leaks 为什么这么说呢?

因为我们在C语言中的内存泄漏,更多是指无法释放的内存。而Java的“内存泄漏”都有明确的引用关系,怎么可能无法释放呢?如果没有了与GC Root的间接或者直接的引用关系,就会被GC回收。有点深,是不是没看懂。我们结合Activity内存泄漏来再次理解下。

每个还在内存中的Activity的实例,如果有引用关系就是泄漏,那么每个Activity都是泄漏,因为他都有被GC Root引用。这里肯定漏了些什么? 为什么leakcanary要监听Activity的生命周期呢?因为这个判断内存泄漏他们添加了一个前提,就是这个Activity的实例走到了Destory了,他应该被GC,但是并没有。

说到这里,我们不妨再抽象下。其实Java的内存问题的核心是,“应然”与“实然”之间矛盾,正如Activity被Destory,他应该被释放,但是实际他没有。来,我们可以放飞下自己的思维了

  1. 内容一样的内存实例,不应该重复出现,实际出现了
  2. 图片的内存占用应该依据屏幕尺寸,但实际超出了

落地到实处,我们在原有的泄露基础上,我们加入了四个对内存优化具有针对性的分析器:

  • 字符串重复
  • Bitmap重复
  • Bitmap超尺寸探测
  • 普通对象重复

除此之外,我们还强化了引用链的分析能力

除开泄露分析器,其他分析器也充分利用上了预加载的最短引用链信息,通过在一组内分析引用链的相似段,找出最普遍的引用链特征,精准定位群体事件的问题所在

让专家真正融入到QAPM中

在我们的日夜兼程的努力下,它完整地融合到了QAPM之中。提供更详细的信息:GC引用链,图片的预览,尺寸,像素通道,字符串的内容等等;并且配合提单系统的修复闭环。下面晒晒界面,也欢迎大家试用。

老页面

列表

详细信息

详细信息

新页面

基于精准的引用链聚合问题,让研发能借助大数据聚焦核心问题

详细的个例信息,助力问题分析

下半部GC引用链

图片预览:可放大查看,直观检查图片尺寸是否合适,是否可以使用RGB565

提单内容自动添加引用链等详细信息

总结,专家vs小白

新内存分析专家 vs. 小白(旧版与LeakCanary 2)

新内存分析

旧内存分析

LeakCanary 2

分析项

多样化,根据分析器制订

少量分析,根据规则制定

仅有泄露

分析结果

针对不同类型有专门化的详细信息(如图片的尺寸,像素信息等)

便利功能

拥有图片预览导出,字符串内容预览等便捷功能

少量

后续规划

虽然目前已经取得了一些成果,但这还远远不够。

  1. 我们需要更多的分析器加入,如对于普通集合类型的低效利用(过短或者持有过多的空引用),引用值类型的分析(java.lang.Integer)等。
  2. 导出更多分析信息(例如针对Bitmap在不同Android版本的信息获取),来更好的定位内存中的问题所在。
  3. 美化信息的输出,提供更加易读,准确的结果。
  4. 考虑提供演进更优的框架设计,获取更好的性能来提升我们的分析体验。
  5. 考虑使用更适合模拟大量小对象的语言进行重写

想了解更多QAPM详情,请咨询:QAPM

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

原创声明:本文系作者授权腾讯云开发者社区发表,未经许可,不得转载。

如有侵权,请联系 cloudcommunity@tencent.com 删除。

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 背景,追赶QAPM的愿景
  • 也许是基于Shark从代码层面的终极性能优化
    • - 分析源码问题
      • - 性能优化: Eager Loading
        • - 性能优化:新索引系统
        • 功能强化,从内存分析小白到内存分析专家
        • 让专家真正融入到QAPM中
          • 老页面
            • 新页面
              • 总结,专家vs小白
              • 后续规划
              领券
              问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档