本原创文章帖发布在华为开发者联盟社区,欢迎开发者前往访问评论交流,更多与该内容相关讨论,请点击原帖查看:

开发态快速定位DMA(ION)泄漏-华为开发者话题 | 华为开发者联盟

1.1 DMA泄漏分析流程与高频泄漏场景

       在HarmonyOS上,DMA内存是指有DMA驱动分配的,支持在多进程、多硬件之间共享访问的RAM内存(特别说明,DMA内存与ION内存是相同的概念)。在HarmonyOS系统中,应用一般通过系统开放的ArkUI、图形和媒体的相关接口间接使用DMA内存,例如ArkUI中的XComponent, Image和Web组件,图形的ImageNative和NativeBuffer,AvCodec的编解码,图片的PixelMap接口等。当应用占用的DMA内存超过阈值时,即认为应用发生DMA内存泄漏。

1.1.1 高频泄漏场景

1.1.1.1 Image控件泄漏或缓存过多导致内存泄漏

       应用程序中的 Image 控件未正确释放DMA内存,引发DMA内存泄漏,最终引发系统图像服务异常或应用崩溃。

1.1.1.2 ArkWeb控件泄漏导致内存泄漏

       应用程序中的 ArkWeb控件未正确管理ArkWeb控件的生命周期或缓存策略,引发DMA内存泄漏,最终引发系统异常或应用崩溃。

1.1.1.3 使用Surface的NDK接口分配内存未释放导致内存泄漏

       应用程序中的Surface的NDK接口分配的DMA内存未释放,引发DMA内存泄漏,最终引发系统异常或应用崩溃。

1.1.1.4 XComponent组件泄漏或者缓存过多导致内存泄漏

       应用程序中的XComponent组件未正确释放DMA内存,或组件缓存无限增长,引发DMA内存泄漏,最终引发系统异常或应用崩溃。

1.1.1.5 视频软硬编解码器API接口使用不当导致内存泄漏

       应用程序中的视频软硬编解码器API接口使用不当导致视频解码/编码时分配的DMA内存未释放,引发DMA内存泄漏,最终引发系统异常或应用崩溃。

1.1.2 标准化排查流程

       1. 复现与日志获取:使用DevEco Profiler的Allocation模板开启统计模式录制泄漏场景,重复多次操作疑似泄漏场景复现问题。

       2. 识别泄漏点: 点击All Anonymous VM中的VM:ION子泳道,在下方详情Call Tree标签页中选择Created & Existing,查看内存占比较高的调用栈。

       3. 分析调用:优先在调用栈信息中寻找占比较高且与业务代码强相关的Symbol Name,即Category中为亮色。根据调用栈分析相关代码(双击跳转源码),排查内存未释放原因。

       4. 代码审查:结合调用栈,梳理相关代码中的内存持有逻辑,定位泄漏根因。

           • 业务逻辑未发现异常:查看DMA内存信息,结合DMA内存信息分析。

           • 业务逻辑存在异常:修改相关代码。

       5. 修复与验证:修改代码后,重复步骤 1,确认内存曲线回归平稳。

图1

1.2 DMA内存泄漏分析案例

1.2.1 案例背景

       现象:本案例中,通过反复操作复现问题场景,观察到应用Graph内存占用呈现"阶梯式持续增长"趋势。

       初步判断:使用 Allocation 统计模式录制内存上涨过程,观察 Memory 泳道中的 Graph 曲线,呈现出典型的“阶梯式增长”,确认存在DMA内存泄漏。

       • Graph 子泳道:应用使用的DMA内存

图2

图3

1.2.2 分析流程

1.2.2.1 步骤1:通过Allocation录制泄漏场景

       1. 基于DevEco Studio Profiler插件的Allocation模板分析堆内存分配、释放的信息,调用栈信息。这些信息中包括已释放内存和未释放内存。启动应用进程,选择Profiler工具 → 选择设备与应用进程 → 选择Allocation模板 → 创建Session → 配置录制选项。

图4

       2. 开启统计模式,可以打开JS栈记录和异步栈记录开关。由于DMA内存的分配频率相比于NaitveHeap的Malloc更低,因此可关闭Malloc采集,减少对DMA内存分析的影响。

图5

       3. 点击按钮启动录制并复现问题场景。

图6

1.2.2.2 步骤2:查看DMA内存调用栈

       1. 框选All Anonymous VM中的VM:ION子泳道。

       • VM:ION子泳道:用于显示DMA内存分配数据。

       2. 在下方详情区的“Statistics”页签中选择Created & Existing。

       • All Allocations:框选的时间段的所有分配内存信息。

       • Created & Existing:默认选中,在框选范围的起点之后分配的,且在框选范围的终点之前没有释放的内存数据。

       • Created & Released:在框选范围的起点之后分配的,且在框选范围的终点之前已经释放的内存数据。

图7

       3. 切换到“Call Trees”页签,该部分数据展示了详细的内存分配栈信息。

图8

1.2.2.3 步骤3:分析DMA内存调用栈

       优先在内存分配栈信息中寻找占比较高且与业务代码强相关的Symbol Name,即Category中为亮色。根据调用栈分析相关代码(双击跳转源码),排查内存未释放原因。

图9

1.2.3 修复验证

       • 修改代码增加 image.PixelMaprelease 方法释放内存。

       • 重新运行应用,再次使用 Allocation 录制内存分配栈。

       • 重复多次操作泄漏场景。

       • 验证结果

          ▪ 每次页面退出后,内存曲线回落至基线。

          ▪ 泄漏问题已修复。

图10

1.3 附录

1.3.1 查看进程中DMA内存信息

       1. 查找进程pid

       启动应用进程,选择Profiler工具 → 选择设备与应用进程,即可看到进程pid。

图11

       2. 获取到pid后,在终端中执行hdc shell,然后执行命令hidumper --mem pid --show-dmabuf 对比复现前和复现后的数据。根据buf_nameleak_type排查相关组件。

图12

       获取指定pid的DMA内存详细信息,开发者可以根据DMA内存信息中的buf_name、leak_type等列定界可疑泄漏组件,参考故障日志分析方法 

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐