想让安卓app不再卡顿?看这篇文章就够了 (3)

我们采用高频采集的方案来获取一段卡顿时间内的多个堆栈,而不再是只有一个点的堆栈。这样的方案的优点是保证了监控的完备性,整个卡顿过程的堆栈都得以采样、收集和落地。

具体做法是在子线程监控的过程中,每一轮log输出或是每一帧开始启动monitor时,我们便已经开启了高频采样收集主线程堆栈的工作了。当下一轮log或者下一帧结束monitor时,我们判断是否发生卡顿(计算耗时是否超过阈值),来决定是否将内存中的这段堆栈集合落地到文件存储。也就是说,每一次卡顿的发生,我们记录了整个卡顿过程的多个高频采样堆栈。由此精确地记录下整个凶案发生的详细过程,供上报后分析处理(后文会阐述如何从一次卡顿中多个堆栈信息中提取出关键堆栈)。

采样频率与性能消耗

目前我们的策略是判断一个卡顿是否发生的耗时阈值是80ms(5*16.6ms),当一个卡顿达80ms的耗时,采集1~2个堆栈基本可以定位到耗时的堆栈。因此采样堆栈的频率我们设为52ms(经验值)。

当然,高频采集堆栈的方案,必然会导致app性能上带来的影响。为此,为了评估对App的性能影响,在上述默认设置的情况下,我们做一个简单的测试实验观察。实验方法:ViVoX9 上运行微信读书App,使用卡顿监控与高频采样,和不使用卡顿监控的情况下,保持两次的操作动作相同,分析性能差异,数据如下:

关闭监控 打开监控 对比情况(上涨)
CPU   1.07%   1.15%   0.08%    
Memory   Native Heap   38794   38894   100 kB  
Dalvik Heap   25889   26984   1095 kB    
Dalvik Other   2983   3099   116 kB    
.so mmap   38644   38744   100 kB    
没有线程快照 加上线程快照
  性能指标   2.4.5.368.91225   2.4.8.376.91678   上涨  
CPU   CPU   63   64   0.97%  
流量KB   Flow   28624   28516    
内存KB   NativeHeap   59438   60183   1.25%  
  DalvikHeap   7066   7109   0.61%  
  DalvikOther   6965   6992   0.40%  
  Sommap   22206   22164    
日志大小KB   file size   294893   1561891   430%  
压缩包大小KB   zip size   15   46   206%  

从实验结果可知,高频采样对性能消耗很小,可以不影响用户体验。

监控使用Choreographer.FrameCallback, 采样频率设52ms),最终结果是性能消耗带来的影响很小,可忽略:

1)监控代码本身对主线程有一定的耗时,但影响很小,约0.1ms/S;

2)卡顿监控开启后,增加0.1%的CPU使用;

3)卡顿监控开启后,增加Davilk Heap内存约1MB;

4)对于流量,文件可按天写入,压缩文件最大约100KB,一天上传一次

痛点2:海量卡顿堆栈后该如何处理?

卡顿堆栈上报到平台后,需要对上报的文件进行分析,提取和聚类过程,最终展示到卡顿平台。前面我们提到,每一次卡顿发生时,会高频采样到多个堆栈信息描述着这一个卡顿。做个最小的估算,每天上报收集2000个用户卡顿文件,每个卡顿文件dump下了用户遇到的10个卡顿,每个卡顿高频收集到30个堆栈,这就已经产生20001030=60W个堆栈。按照这个量级发展,一个月可产生上千万的堆栈信息,每个堆栈还是几十行的函数调用关系。这么大量的信息对存储,分析,页面展示等均带来相当大的压力。很快就能撑爆存储层,平台无法展示这么大量的数据,开发更是没办法处理这些多的堆栈问题。因而,海量卡顿堆栈成为我们另外一个面对的难题。

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/zypwgj.html