欢迎来到尧图网

客户服务 关于我们

您的位置:首页 > 新闻 > 焦点 > HarmonyOS开发中,如何高效定位并分析内存泄露相关问题

HarmonyOS开发中,如何高效定位并分析内存泄露相关问题

2024/12/22 21:42:14 来源:https://blog.csdn.net/wy363681759/article/details/143750015  浏览:    关键词:HarmonyOS开发中,如何高效定位并分析内存泄露相关问题

HarmonyOS开发中,如何高效定位并分析内存泄露相关问题

  • (1)Allocation的应用
    • 调试方式
    • Memory泳道
    • Native Allocation泳道
  • (2)Snapshot
  • (3)ASan的应用
    • 使用约束
    • 配置参数
    • 使能ASan
      • 方式一
      • 方式二
    • 启用ASan
    • ASan检测异常码
  • (4)HWASan的应用
    • 功能介绍
    • 约束条件
    • 使能HWASan
      • 方式一
      • 方式二
    • 启用HWASan
  • 总结

应用在开发过程中,可能会因为API使用错误、变量未及时释放、异常频繁创建/释放内存等情况引发各种内存问题。
华为官方提供了多种方案来方便各位开发者分析解决内存相关问题,比如Allocation (获取native调用栈profiler)、SnapShot、ASan、HWASan,本文重点对这些工具的特点做些说明,同时结合实际案例对这些工具的应用做进一步讲解。

(1)Allocation的应用

Allocation是DevEco Studio 开发工具的 Profiler提供的内存场景分析工具,开发过程中可以使用Allocation来分析应用或服务在运行时的内存分配及使用情况,识别和定位内存泄漏、内存抖动以及内存溢出等问题,对应用或服务的内存使用进行优化。

调试方式

打开 DevEco Studio 找到 Profiler,DevEco Profiler提供Launch、ArkUI、Frame、Concurrency、ArkWeb、Network、Time、Allocation、Snapshot、CPU等场景化分析任务类型,在设备列表中选择设备(目前只支持真机),在进程列表中选择要调测的应用,选择Allocation并点击Create Session即可创建一次会话。右侧任务分析窗口可以选择Memory、Native Allocation具体分析。
![在这里插入图片描述](https://i-blog.csdnimg.cn/direct/7e0298bf884148d7b3facba13ac95332.png

Memory泳道

可以看到Memory泳道包含三个标识:PSS代表进程独占内存和按比例分配共享库占用内存之和,RSS是进程独占内存和相关共享库占用内存之和,USS代表进程独占内存。

在右边录制详情区域,工具控制栏上有很多小图标,鼠标放上去会有一些功能提示,可以添加一些录制选项,各泳道区域也有下拉框选项,下拉选择不同的设置可以调整录制功能。

单击任务窗口左上角的 ,启动录制,也可以选择左侧的任务列表中的,启动录制后,等待任务状态由“initializing”变为“recording”。录制过程中整个DevEco Profiler不能再点击其他的模板进行操作,如果想录制其他模板可以结束本次录制重新选择其他模板开始录制。
在这里插入图片描述
录制过程中,右侧任务分析窗口显示未recording状态,先要结束此次录制时,点击左侧Allocation按钮的stop按钮即可,结束录制之后可以看到当前session的各个不同内存类型对应的变化情况。
默认展示其中的五个子泳道,如要显示其他子泳道,可以点击主泳道的options标签并勾选其他泳道来查看。在这里插入图片描述
选择具体的子泳道可以在details模块看到不同的时间点,对应的内存值变化情况,方便开发者进一步定位问题。
在这里插入图片描述
特别提示:

  • 由于隐私安全政策,已上架应用市场的应用不支持录制此泳道。
  • 建议避免同时录制ArkTS Allocation及Native Allocation泳道,避免影响分析准确性。

Native Allocation泳道

Native Allocation泳道主要显示具体的Native内存分配情况,包括静态统计数据、分配栈、每层函数栈消耗的Native内存等信息。由于隐私安全政策,已上架应用市场的应用不支持录制此泳道。通过操作对应的options同样可以选择展示的类型,框选子泳道后显示具体的内存分配,包括静态统计数据、分配栈等。
在这里插入图片描述

如下图所示,为选中Native Allocation后的某种展示场景。

  • Statistics显示该段时间内的静态分配情况。包括分配方式(Malloc或Mmap)、总分配内存大小、总分配次数、尚未释放的内存大小、尚未释放次数、已释放的内存大小、已释放次数。
    点击任意对象上的跳转按钮,可跳转至此类对象的详细占用/分配信息。当前统计模式下不支持跳转。
  • Call Trees页签显示线程的内存分配栈情况。包括函数地址或符号、分配大小、占比以及函数栈帧的类别等。单击任一行栈帧,“More”区域将显示经过该栈帧的分配内存最大的调用栈。
  • Allocations List显示内存分配的详细信息。包括内存块起始地址、时间戳、当前活动状态、大小、调用的库、调用库的具体函数、事件类型(与Statistics页签的分配方式对应)等。

针对详情面板中所展示的函数栈帧信息(如下图所示),双击栈帧结点,工具便会在编辑器中打开相关源码文件,并定位到对应行号。此功能正常使用的前提是用于抓取性能数据的应用,是在DevEco Studio所在的开发环境中编译,且相关源文件位置并未改变。
在这里插入图片描述
值得注意的是,上图对应的category列表标识调用栈的类型,从语言层面分为ArkTS、NAPI以及Native,从归属层面分为开发者代码以及系统代码(如下图所示)。从这两个方面可以将调用栈类型归类如下:

  • ArkTS:程序正在执行ArkTS代码;
  • NAPI:程序正在运行的NAPI代码;
  • Native:程序正在执行的Native代码;其中每一个类型的亮色和灰色分别代表开发者和系统的代码。
    在这里插入图片描述

Native Allocation泳道的内存状态信息可以进一步过滤和筛选。选中Native Allocation后,details底部有两个默认过滤条件All Allocations、Native Size。

  • All Allocations(默认状态):详情区域展示当前框选时间段内的所有内存分配信息

  • Created & Existing:详情区域展示当前框选时间段内分配未释放的内存。

  • Created & Released:详情区域展示当前框选时间段内分配已释放的内存。
    在这里插入图片描述

  • Native Size:详情区域按照对象的原生内存进行展示。

  • Native Library:详情区域按照对象的so库进行展示。
    在这里插入图片描述

此外,在“Native Allocation”泳道的“Allocations List”页签中还可以通过so库名称进行筛选、搜索关键词筛选、内存分配堆栈进行筛选,此处不再做过多演示。

关于Allocation的更多介绍和使用方法可以在官方文档查看,基础内存分析:Allocation分析

(2)Snapshot

Snapshot是DevEco Profiler提供的一个内存快照分析工具,通过结合Memory实时占用情况,分析不同时刻的方舟虚拟机内存对象占用情况及差异,进而进行内存优化。

关于Snapshot具体的应用技巧可以借鉴官网Snapshot模板基本操作,或者借鉴使用Snapshot Insight分析ArkTS内存问题,本文不再赘述。

(3)ASan的应用

ASan(Address-Sanitizer)是内存检测的工具,用于发现内存飞踩第一现场,DevEco Studio为开发者集成了ASan能力,可以检测C/C++的地址越界问题,解决一些踩内存导致的异常crash的补充手段,对于一些明显不可能crash的场景可以尝试开启ASan。

使用约束

  • 如果应用内的任一模块使能ASan,那么entry模块需同时使能ASan。
  • 如果entry模块未使能ASan,该应用在启动时将闪退,出现CPP Crash报错。
  • ASan、TSan、HWASan不能同时开启,三个只能开启其中一个。

配置参数

ASAN_OPTIONS:在运行时配置ASan的行为,包括设置检测级别、输出格式、内存错误报告的详细程度等。ASAN_OPTIONS支持在app.json5中配置,也支持在Run/Debug Configurations中配置。app.json5的优先级较高,即两种方式都配置后,以app.json5中的配置为准。

以在app.json5中配置环境变量为例。打开AppScope > app.json5文件,添加配置示例如下。

{"app": {"appEnvironments": [{"name": "ASAN_OPTIONS","value": "log_exe_name=true abort_on_error=0 print_cmdline=true" // 示例仅供参考,具体以实际为准},],...}
}

在Run/Debug Configurations中配置环境变量,具体可查看配置环境变量

使能ASan

可通过以下两种方式使能ASan。

方式一

  1. 在运行调试窗口(entry --> Edit Configurations),点击Diagnostics,勾选Address Sanitizer。
    在这里插入图片描述
    在这里插入图片描述
  2. 如果有引用本地library,需在library模块的build-profile.json5文件中,配置arguments字段值为“-DOHOS_ENABLE_ASAN=ON”,表示以ASan模式编译so文件。
    在这里插入图片描述

方式二

  1. 修改工程目录下AppScope/app.json5,添加ASan配置开关。
 "asanEnabled": true

在这里插入图片描述

  1. 设置模块级构建ASan插桩。
    在需要使能ASan的模块中,通过添加构建参数开启ASan检测插桩,在对应模块的模块级build-profile.json5中添加命令参数:
"arguments": "-DOHOS_ENABLE_ASAN=ON"

在这里插入图片描述

启用ASan

运行或调试当前应用。
当程序出现内存错误时,弹出ASan log信息,点击信息中的链接即可跳转至引起内存错误的代码处。

举例说明:
编写一段数组越界的C++代码,对外暴露接口,在ArkTs侧调用该方法。
在这里插入图片描述

Text(this.message).fontSize(50).fontWeight(FontWeight.Bold).onClick(() => {hilog.info(0x0000, 'testTag', 'Test NAPI 2 + 3 = %{public}d', testNapi.add(2, 3));hilog.info(0x0000, 'testTag', 'HeapBufferOverflow() ', testNapi.HeapBufferOverflow());// this.memoryLeak()})

运行当前项目,触发Button的onClick事件调用之后,应用崩溃,弹出FaultLog信息。
在这里插入图片描述
点击 Jump to Log跳转到FaultLog模块。
在这里插入图片描述

可以看到log信息有明确的log信息,报错原因为“AddressSanitizer: heap-buffer-overflow”,同样的还有多个链接地址。“appspawn30149==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x005b7fe7153b at pc 0x007c24fc309c bp 0x007eba84b160 sp 0x007eba84b158
”可以直接跳转到官网关于“heap-buffer-overflow”的报错解释以及解决方案。另外多个包含“/data/storage/el1/…”的地址能精确定位到C/C++层代码出错的具体位置。
在这里插入图片描述
然后我们就发现这是数组越界造成的,所以解决方案就是“对于已知大小的集合,注意访问不要越界,位置大小的集合访问前先判断大小。”

ASan检测异常码

ASan不仅能检测出“heap-buffer-overflow”异常,还能检测很多其他类型的内存异常,关于这些异常问题及解决方案,如下所示。

  • heap-buffer-overflow

    • 背景/原理:访问越界。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:AddressSanitizer:heap-buffer-overflow
    • 修改方法:注意数组容量不要访问越界。
    • 推荐建议:已知大小的集合注意访问不要越界,位置大小的集合访问前先判断大小。
  • stack-buffer-underflow

    • 背景/原理:访问越下界。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:AddressSanitizer:stack-buffer-underflow
    • 修改方法:访问索引不应小于下界。
    • 推荐建议:访问索引不应小于下界。
  • stack-use-after-scope

    • 背景/原理:栈变量在作用域之外被使用。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:AddressSanitizer:stack-use-after-scope
    • 修改方法:在作用域内使用该变量。
    • 推荐建议:注意变量作用域。
  • attempt-free-nonallocated-memory

    • 背景/原理:尝试释放了非堆对象(non-heap object)或未分配内存。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:
      AddressSanitizer: attempting free on address which was not malloc()-ed
    • 修改方法:不要对非堆对象或未分配的内存使用free函数。
    • 推荐建议:不要对非堆对象或未分配的内存使用free函数。
  • double-free

    • 背景/原理:重复释放内存。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:
      AddressSanitizer: double-free
    • 修改方法:已经释放一次的指针,不要再重复释放。
    • 推荐建议:变量定义声明时初始化为NULL,释放内存后也应立即将变量重置为NULL,这样每次释放之前都可以通过判断变量是否为NULL来判断是否可以释放。
  • heap-use-after-free

    • 背景/原理:当指针指向的内存被释放后,仍然通过该指针访问已经被释放的内存,就会触发heap-use-after-free。
    • 影响/报错:导致程序存在安全漏洞,并有崩溃风险。
      开启ASan检测后,触发demo中的函数,应用闪退报ASan,包含字段:
      AddressSanitizer: heap-use-after-free
    • 修改方法:已经释放的指针不要再使用,将指针设置为NULL/nullptr。
    • 推荐建议:实现一个free()的替代版本或者 delete析构器来保证指针的重置。
  • Other categories
    未知的错误类型,持续更新中。

(4)HWASan的应用

HWASan(Hardware-Assisted Address Sanitizer)是一款类似于ASan的内存错误检测工具,目前仅适用于。 与ASan相比,HWASan使用的内存减少很多,因而更适合用于整个系统的清理。

功能介绍

与ASan相比,HWASan具有如下特征:

  • CPU开销约为2倍。
  • 代码大小开销为40% - 50%。
  • RAM开销为10% - 35%。

HWASan能检测到ASan所能检测到的同一系列错误:

  • 堆栈和堆缓冲区上溢/下溢。
  • 释放之后的堆使用情况。
  • 重复释放/错误释放。

和ASan相比,HWASan具有以下优点:

  • HWASan不需要安全区来检测buffer overflow,既极大地降低了工具对于内存的消耗,也不会出现ASan中某些overflow检测不到的情况。
  • HWASan不需要隔离区来检测UseAfterFree,因此不会出现ASan中某些UseAfterFree检测不到的情况。
  • 此外,HWASan还可以检测返回之后的堆栈使用情况。

约束条件

  • HWASan检测仅适用于AArch64架构的硬件。
  • ASan、TSan、HWASan不能同时开启,三个只能开启其中一个。

使能HWASan

方式一

在运行调试窗口(例如entry --> Edit Configurations),点击Diagnostics,勾选Hardware-Assisted Address Sanitizer开启检测。

在这里插入图片描述

方式二

修改工程目录下的AppScope/app.json5文件,添加HWASan配置开关。

"hwasanEnabled": true

在这里插入图片描述
在需要使能HWASan的模块中,通过添加构建参数开启HWASan检测插桩,在对应模块的模块级build-profile.json5中添加命令参数:

"arguments": "-DOHOS_ENABLE_HWASAN=ON"

在这里插入图片描述

启用HWASan

运行或调试当前应用。当程序出现内存错误时,弹出HWASan log信息,点击信息中的链接即可跳转至引起内存错误的代码处。

关于HWAan的代码实例和应用场景基本和ASan一致,此处就不做重复是说明了。

总结

  • 根据Allocation分析的结果,可以方便开发者优化应用的服务和组件的内存使用。例如,减少不必要的内存分配和释放,优化数据结构的使用等。

  • 通过ASan或HWASan分析问题时,精准定位内存出错原因和具体位置,开发者应修复这些内存管理的问题,如确保所有分配的内存都被正确释放。

  • 开发过程中,使用合适的内存管理和回收机制 :确保应用在不需要内存资源时能够有效地回收和管理这些资源,避免过度使用内存。

版权声明:

本网仅为发布的内容提供存储空间,不对发表、转载的内容提供任何形式的保证。凡本网注明“来源:XXX网络”的作品,均转载自其它媒体,著作权归作者所有,商业转载请联系作者获得授权,非商业转载请注明出处。

我们尊重并感谢每一位作者,均已注明文章来源和作者。如因作品内容、版权或其它问题,请及时与我们联系,联系邮箱:809451989@qq.com,投稿邮箱:809451989@qq.com