注意: 开启内存检测会影响内存申请的性能,且每个内存节点都会记录LR地址,内存开销也加大。

编程实例

本实例实现如下功能:构建内存泄漏代码段。

  1. 调用LOS_MemUsedNodeShow接口,输出全部节点信息打印;

  2. 申请内存,但没有释放,模拟内存泄漏;

  3. 再次调用LOS_MemUsedNodeShow接口,输出全部节点信息打印;

  4. 将两次log进行对比,得出泄漏的节点信息;

  5. 通过LR地址,找出泄漏的代码位置;

示例代码

代码实现如下:

本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemLeakTest。

qemu平台运行时需确保target_config.h 中对应的LOSCFG_MEM_FREE_BY_TASKID为0。

由于打开内存检测后,部分平台有其他任务运行,会频繁调用内存相关打印如:psp, start = xxxxx, end = xxxxxxx,请忽略打印或删除OsStackAddrGet函数中调用的打印即可。

#include 
#include 
#include "los_memory.h"
#include "los_config.h"

void MemLeakTest(void)
{
    LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
    void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    LOS_MemUsedNodeShow(LOSCFG_SYS_HEAP_ADDR);
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
结果验证

编译运行输出示例log如下:

node         size   LR[0]       LR[1]       LR[2]   
0x20001b04:  0x24   0x08001a10  0x080035ce  0x080028fc 
0x20002058:  0x40   0x08002fe8  0x08003626  0x080028fc 
0x200022ac:  0x40   0x08000e0c  0x08000e56  0x0800359e 
0x20002594:  0x120  0x08000e0c  0x08000e56  0x08000c8a 
0x20002aac:  0x56   0x08000e0c  0x08000e56  0x08004220 

node         size   LR[0]       LR[1]       LR[2]   
0x20001b04:  0x24   0x08001a10  0x080035ce  0x080028fc 
0x20002058:  0x40   0x08002fe8  0x08003626  0x080028fc 
0x200022ac:  0x40   0x08000e0c  0x08000e56  0x0800359e 
0x20002594:  0x120  0x08000e0c  0x08000e56  0x08000c8a 
0x20002aac:  0x56   0x08000e0c  0x08000e56  0x08004220 
0x20003ac4:  0x1d   0x08001458  0x080014e0  0x080041e6 
0x20003ae0:  0x1d   0x080041ee  0x08000cc2  0x00000000

根据实际运行环境,上文中的数据会有差异,非固定结果
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

对比两次log,差异如下,这些内存节点就是疑似泄漏的内存块:

0x20003ac4:  0x1d   0x08001458  0x080014e0  0x080041e6 
0x20003ae0:  0x1d   0x080041ee  0x08000cc2  0x00000000

根据实际运行环境,上文中的数据会有差异,非固定结果
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

部分汇编文件如下:

                MemLeakTest:
  0x80041d4: 0xb510         PUSH     {R4, LR}
  0x80041d6: 0x4ca8         LDR.N    R4, [PC, #0x2a0]       ; g_memStart
  0x80041d8: 0x0020         MOVS     R0, R4
  0x80041da: 0xf7fd 0xf93e  BL       LOS_MemUsedNodeShow    ; 0x800145a
  0x80041de: 0x2108         MOVS     R1, #8
  0x80041e0: 0x0020         MOVS     R0, R4
  0x80041e2: 0xf7fd 0xfbd9  BL       LOS_MemAlloc           ; 0x8001998
  0x80041e6: 0x2108         MOVS     R1, #8
  0x80041e8: 0x0020         MOVS     R0, R4
  0x80041ea: 0xf7fd 0xfbd5  BL       LOS_MemAlloc           ; 0x8001998
  0x80041ee: 0x0020         MOVS     R0, R4
  0x80041f0: 0xf7fd 0xf933  BL       LOS_MemUsedNodeShow    ; 0x800145a
  0x80041f4: 0xbd10         POP      {R4, PC}
  0x80041f6: 0x0000         MOVS     R0, R0

  根据实际运行环境,上文中的数据会有差异,非固定结果
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

其中,通过查找0x080041ee,就可以发现该内存节点是在MemLeakTest接口里申请的且是没有释放的。

踩内存检测

基础概念

踩内存检测机制作为内核的可选功能,用于检测动态内存池的完整性。通过该机制,可以及时发现内存池是否发生了踩内存问题,并给出错误信息,便于及时发现系统问题,提高问题解决效率,降低问题定位成本。

功能配置

LOSCFG_BASE_MEM_NODE_INTEGRITY_CHECK:开关宏,默认关闭;若打开这个功能,在target_config.h中将这个宏定义为1。

  1. 开启这个功能,每次申请内存,会实时检测内存池的完整性。

  2. 如果不开启该功能,也可以调用LOS_MemIntegrityCheck接口检测,但是每次申请内存时,不会实时检测内存完整性,而且由于节点头没有魔鬼数字(开启时才有,省内存),检测的准确性也会相应降低,但对于系统的性能没有影响,故根据实际情况开关该功能。

由于该功能只会检测出哪个内存节点被破坏了,并给出前节点信息(因为内存分布是连续的,当前节点最有可能被前节点破坏)。如果要进一步确认前节点在哪里申请的,需开启内存泄漏检测功能,通过LR记录,辅助定位。

注意: 开启该功能,节点头多了魔鬼数字字段,会增大节点头大小。由于实时检测完整性,故性能影响较大;若性能敏感的场景,可以不开启该功能,使用LOS_MemIntegrityCheck接口检测。

开发指导

开发流程

通过调用LOS_MemIntegrityCheck接口检测内存池是否发生了踩内存,如果没有踩内存问题,那么接口返回0且没有log输出;如果存在踩内存问题,那么会输出相关log,详见下文编程实例的结果输出。

编程实例

本实例实现如下功能:

  1. 申请两个物理上连续的内存块;

  2. 通过memset构造越界访问,踩到下个节点的头4个字节;

  3. 调用LOS_MemIntegrityCheck检测是否发生踩内存。

示例代码

代码实现如下:

本演示代码在 ./kernel/liteos_m/testsuites/src/osTest.c 中编译验证,在TestTaskEntry中调用验证入口函数MemIntegrityTest。

qemu平台运行时需确保target_config.h 中对应的LOSCFG_MEM_FREE_BY_TASKID为0。

由于执行时主动触发异常,执行结束后需要重启qemu(例如打开一个新的终端界面输入killall qemu-system-arm)

#include 
#include 
#include "los_memory.h"
#include "los_config.h"

void MemIntegrityTest(void)
{
    /* 申请两个物理连续的内存块 */
    void *ptr1 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    void *ptr2 = LOS_MemAlloc(LOSCFG_SYS_HEAP_ADDR, 8);
    /* 第一个节点内存块大小是8字节,那么12字节的清零,会踩到第二个内存节点的节点头,构造踩内存场景 */
    memset(ptr1, 0, 8 + 4);
    LOS_MemIntegrityCheck(LOSCFG_SYS_HEAP_ADDR);
}
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">
结果验证

编译运行输出log如下:

/* 提示信息,检测到哪个字段被破坏了,用例构造了将下个节点的头4个字节清零,即魔鬼数字字段 */
[ERR][IT_TST_INI][OsMemMagicCheckPrint], 1664, memory check error!
memory used but magic num wrong, magic num = 0x0

 /* 被破坏节点和其前节点关键字段信息,分别为其前节点地址、节点的魔鬼数字、节点的sizeAndFlag;可以看出被破坏节点的魔鬼数字字段被清零,符合用例场景 */
 broken node head: 0x2103d7e8  0x0  0x80000020, prev node head: 0x2103c7cc  0xabcddcba  0x80000020

 /* 节点的LR信息需要开启前文的内存泄漏检测功能才有有效输出 */
 broken node head LR info:
 LR[0]:0x2101906c
 LR[1]:0x0
 LR[2]:0x0

 /* 通过LR信息,可以在汇编文件中查找前节点是哪里申请,然后排查其使用的准确性 */
 pre node head LR info:
 LR[0]:0x2101906c
 LR[1]:0x0
 LR[2]:0x0

 /* 被破坏节点和其前节点的地址 */
[ERR][IT_TST_INI]Memory integrity check error, cur node: 0x2103d784, pre node: 0x0

 根据实际运行环境,上文中的数据会有差异,非固定结果
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}"> class="hide-preCode-box">

如果大家想更加深入的学习 OpenHarmony(鸿蒙南向) 开发的全栈内容,不妨可以参考以下相关学习文档进行学习,助你快速提升自己:

OpenHarmony 开发环境搭建:https://qr18.cn/CgxrRy

《OpenHarmony源码解析》:https://qr18.cn/CgxrRy

系统架构分析:https://qr18.cn/CgxrRy

OpenHarmony 设备开发学习手册:https://qr18.cn/CgxrRy

在这里插入图片描述

OpenHarmony面试题(内含参考答案):https://qr18.cn/CgxrRy

写在最后

data-report-view="{"mod":"1585297308_001","spm":"1001.2101.3001.6548","dest":"https://blog.csdn.net/maniuT/article/details/140896644","extend1":"pc","ab":"new"}">>
注:本文转载自blog.csdn.net的沧海一笑-dj的文章"https://blog.csdn.net/dengjin20104042056/article/details/97690456"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!