本系列文章旨在提供定位与解决OpenHarmony应用与子系统内存泄露的常见手段与思路,将会分成几个部分来讲解。首先我们需要掌握发现内存泄漏问题的工具与方法,以及判断是否可能存在泄漏。接着需要掌握定位泄漏问题的工具,以及抓取trace、分析trace,以确定是否有泄漏问题。如果发现问题的场景过于复杂,需要通过分解问题来简化场景。最后根据trace来找到问题代码并尝试解决。

目录:

  1. 发现问题
  2. 定位问题
  3. 分析Trace
  4. 分解问题
  5. 解决问题(Native)
  6. 解决问题(NAPI&JavaScript)
  7. 解决问题(综合)

有些时候,在我们抓取了native或js的trace后,创建栈非常多非常密集,可能是好几个问题都集中到一起,比较难以通过肉眼筛选出关键对象。这时候时间轴内的曲线通常也毫无规律,没法准确区分每次操作的间隔在哪,干扰判断。因此我们需要将复杂的问题分解为一个个简单的问题,方便分析。

由于场景复杂的通常是应用,系统服务的场景比较单一,而且不会有UI造成干扰,抓取的trace相对而言比较清晰,因此下文主要针对应用做分解。

最小化场景

最小化场景的目的是为了保证trace清晰,避免过多的创建栈干扰视线。为了达到这个目的,我们可以尝试通过如下方式构造最小化场景。

按功能分解

如果在应用测试时,发现应用进程可能存在泄漏,而应用功能又比较复杂,比如SystemUi。此时可以按功能单独进行测试,并观察每个功能经过反复调用后的内存情况。

如果发现某一功能存在泄漏,但是抓取的trace还是比较难以排查,则需要按更小的粒度继续拆解该功能。比如设置应用中的wifi设置功能,又可以被拆解为wifi开启、关闭、连接、断开等小功能。

修改代码

如果某个可疑场景已经无法简单的按独立的功能进行分解,就需要通过修改代码来达到分解的目的。这需要对业务代码有一定的熟悉。

  • 屏蔽代码中的所有api调用,来确定是否是UI造成的泄漏。
  • 在毫无头绪的情况下,可以将页面组件分为上下两部分,屏蔽后分别进行测试,缩小范围。类似于二分。
  • 在trace中占比很大的对象,或创建对象类型多的代码,可以先注释掉,优先分析简单的部分。
  • 不要忽略框架提供的基础能力,如状态管理等可能引起的泄漏,可以仅保留如,与状态管理变量相关的代码进行分析。

提取代码

通过空应用可以很方便的构造出最小化场景:

  • 如怀疑某一组件、API存在泄漏,可以通过提取代码至空应用内,单独针对其分析。
  • 大胆假设应用框架存在问题,比如某个页面跳转的场景可能存在泄漏,可以先针对空页面跳转进行分析。

案例

SystemUI的分解

在3.2 beta4版本,SystemUI单应用测试的内存占用,可以在较短时间内达到300M,存在很大的泄漏。但是SystemUI本身有多个Hap组成,功能复杂,代码量大。因此不对其做场景分解的话,很难入手去解决。

初步分析

通过观察DevEco Testing工具的测试过程,发现主要有如下几个测试场景:

  • 下拉通知面板

    img

  • 进入通知管理页面

    img

  • 下拉控制中心

    img

  • 进入快捷开关并返回

    img

因此初步将场景拆分为4个,通过手动反复操作,以及hidumper观察内存占用,选择一个增长最快的场景深入分析。

通知管理

上面4个场景中,反复进入退出通知管理页面,内存增长最快。由于页面元素较多,因此还需要拆分。

空页面

首先想到的就是,如果一个空的Ability加上空的ArkUI页面,会不会也存在泄漏?此时可以写一个空应用,从AbilityA跳转至AbilityB,再返回。如此反复测试,发现内存也会增长,由此能初步判断应用框架存在泄漏。由于是空应用,代码少,场景单一,因此无需再分解。后续通过trace分析发现,元能力与窗口子系统存在泄漏。

组件

在解决了应用框架的泄漏后,重新测试该页面,发现还是存在少量的泄漏。此时需要继续拆分页面:将页面分为上下两部分,上部分为除开列表的其他组件,下部分为列表。通过此方法不停的细化场景,最终发现部分ArkUI组件存在泄漏。

解决后再重新测试发现内存已经能稳定在一个范围内。

通知面板

通知面板除开第一次下拉时内存会有明显增长外,后续也相对稳定,并且页面比较简单,没有其他可操作的场景,因此暂时不分析。

控制中心

控制中心页面有非常多的操作按钮,虽然在下拉这个场景内存相对稳定,但是其他场景也不能忽略。因此手动测试每个按钮,包括截屏、更改亮度、打开关闭蓝牙啊、wifi等等场景。最终发现在点击开启关闭位置按钮时,内存稳定增长。通过分析发现位置子系统存在内存泄漏。

快捷开关

反复进入快捷开关页面,内存增长也比较迅速。通过分析该页面是由if-else来控制页面显示隐藏达到切换页面的目的,且带有切换动画,页面结构较为复杂,因此需要拆分:

  • 完全去掉下方的操作面板,只保留返回按钮与标题,发现内存仍会增长。
  • 通过一点点的减少代码,缩小范围,最后锁定在@Prop配合if-else等会创建销毁组件的语法使用时,会造成泄漏。
  • 解决上述问题后,再一点点加回代码,看加回哪些组件后,内存会增长。
  • 后续发现部分API使用错误的代码,造成泄漏。

解决完上述问题后,重新最SystemUI整体压测,内存占用有了极大的缓解。

总结

在泄漏场景比较大,比较复杂时,我们需要想各种办法来拆分场景,结合第一篇如何发现问题,来重点定位于分析可疑场景的相关代码。这是一个递归的过程:不断的分解场景,直到场景足够单一,代码足够简单,或trace足够清晰。

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐