利用mtrace检查内存泄漏

mtrace是linux下检查内存泄漏的工具之一。

    它实际上是通过一对函数来检测一段代码是否存在内存泄漏:

    mtrace()与muntrace()。

    它们的原型如下:

    void mtrace(void);

    void muntrace(void);

    头文件为:mcheck.h

    用法:

   1. 首先确定需要检测那一段代码

   2. 然后再在这段代码的前面调用mtrace(),在这段代码之后调用muntrace()。

   3. 设置环境变量:MALLOC_TRACE,可以在程序编译好后通过命令:

      export MALLOC_TRACE=./log   //其中log是用来存放内存泄漏信息的日志文件名。

      也可以在调用mtrace()之前调用函数设置环境变量:setenv("MALLOC_TRACE", "log", 1);

   4. 编译并运行程序,这样内存泄漏信息就会写到log文件中。

   5. 查看log文件,如:cat log

注意: 一般情况下不要调用muntrace, 而让程序自然结束. 因为可能有些释放内存代码要到muntrace之后才运行.

实例:

#include <stdio.h>

#include <error.h>

#include <mcheck.h>

int main(void)

{

    setenv("MALLOC_TRACE", "log", 1);   //设置环境变量MALLOC_TRACE

    mtrace();   //在需要检测的代码段之前调用mtrace函数

    char *str1 = (char*)malloc(10);

     char *str2 = (char*)malloc(10);

    if((NULL == str1) || (NULL == str2))

    {

        perror("can't allocate memory");

    }

    muntrace();    //在需要检测的代码段之后调用muntrace函数

    return 0;

}

将上面的程序编译运行后会在当前目录下产生一个记录=内存泄漏的文件log,其内容如下:

(“+”表示申请的内存,“-”表示释放的内存)

= Start
@ ./test:[0x8048534] + 0x9ed1418 0xa
@ ./test:[0x8048542] + 0x9ed1428 0xa
= End

上面的信息表示:程序分配了两次内存,起内存地址分别是0x9ed1418和0x9ed1428;但并未释放,于是这段程序就存在内存泄漏。

现在我们在示例程序中加上一句:free(str1); 再编译运行后查看log如下:

= Start
@ ./test:[0x8048564] + 0x91ab418 0xa
@ ./test:[0x8048572] + 0x91ab428 0xa
@ ./test:[0x804859c] - 0x91ab418
= End

上面的信息表示:程序申请了两块内存0x91ab418和0x91ab428,但只释放了内存0x91ab418 。故也存在内存泄漏。

当然如果加上free(str1); 与free(str2);则log内容如下:

= Start
@ ./test:[0x8048564] + 0x809b418 0xa
@ ./test:[0x8048572] + 0x809b428 0xa
@ ./test:[0x804859c] - 0x809b418
@ ./test:[0x80485a4] - 0x809b428
= End

这表示申请的内存都释放掉了,故不存在内存泄漏。


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/gogor/archive/2009/09/03/4515131.aspx

<think>好的,用户问的是嵌入式开发中如何检查内存泄漏的方法和工具。我需要先回忆一下嵌入式系统内存管理的特点,通常资源有限,有桌面系统那么强大的工具,所以方法和工具可能更注重轻量级和实时性。 首先,用户可能是在开发过程中遇到了内存泄漏的问题,或者想提前预防。他们可能是嵌入式开发的新手,或者有一定经验但想了解更多工具。需要分步骤解释,从手动检查工具使用,逐步深入。 手动检查方面,可以提到代码审查,特别是malloc/free或new/delete的配对使用。另外,嵌入式系统可能使用静态内存分配,或者内存池,这样可以减少泄漏的可能。但动态分配有时不可避免,所以需要其他方法。 然后,日志跟踪法,记录每次内存分配和释放的信息,比如文件名、行号、大小等,这样在运行时或后期分析时可以对比是否有未释放的内存。这对资源有限的嵌入式设备可能增加开销,但可以调试时开启。 接下来,工具部分。Valgrind虽然强大,但在嵌入式环境可能不太适用,因为通常运行在PC端,交叉编译的程序可能需要仿真环境,比如QEMU。这时候可能需要解释如何在目标设备上使用类似工具MTrace是GCC自带的,可能更适合,但需要用户设置钩子函数和生成日志文件,然后通过mcheck来分析。这对于支持GLIBC的环境可行,但某些嵌入式系统可能使用其他库,如uClibc,可能不支持。 ARM的DS-5 Streamline,这个工具针对ARM架构,可以进行性能分析,包括内存泄漏检测。用户如果使用ARM芯片,这可能是个好选择。 Embedded Profiler(Emlog)这类轻量级工具,适合资源受限的环境,实时监控内存使用情况,帮助定位泄漏点。需要说明其适用场景。 内存保护单元(MPU)或硬件断点,通过硬件监控内存访问,当发生越界或重复释放时触发异常。这需要硬件支持,可能在某些高端微控制器上可用。 内存统计功能,比如重写malloc/free,统计当前分配的内存块数量和大小,定期输出,观察是否有持续增长的情况。这对资源消耗较小,适合长期运行测试。 此外,可能还需要提到一些最佳实践,比如在嵌入式系统中尽量避免动态内存分配,使用静态分配或内存池,减少泄漏风险。或者在测试阶段进行长时间的压力测试,观察内存变化。 还要注意不同嵌入式操作系统的工具,比如FreeRTOS、VxWorks等可能有自己的内存诊断工具。例如,FreeRTOS提供了内存统计的API,可以获取堆的使用情况。 用户可能需要具体的步骤,比如如何配置MTrace,或者如何重写malloc函数添加跟踪信息。但根据问题,可能不需要太深入,先给出方法和工具列表,如果有进一步的问题再详细说明。 最后,总结一下各种方法的优缺点,比如手动检查适合小型项目,工具适用于不同环境和资源条件,帮助用户根据具体情况选择合适的方法。</think>在嵌入式开发中,内存泄漏检测需要结合轻量化工具和针对性方法,以下是5种典型方案及操作示例: 一、内存分配追踪法(无工具依赖) ```c // 重定义malloc/free函数并添加追踪信息 #define TRACK_SIZE 100 typedef struct { void* ptr; size_t size; const char* file; int line; } AllocRecord; AllocRecord alloc_list[TRACK_SIZE]; int alloc_count = 0; void* tracked_malloc(size_t size, const char* file, int line) { void* ptr = malloc(size); if(alloc_count < TRACK_SIZE) { alloc_list[alloc_count].ptr = ptr; alloc_list[alloc_count].size = size; alloc_list[alloc_count].file = file; alloc_list[alloc_count].line = line; alloc_count++; } return ptr; } void tracked_free(void* ptr) { for(int i=0; i<alloc_count; i++) { if(alloc_list[i].ptr == ptr) { free(ptr); alloc_list[i] = alloc_list[--alloc_count]; return; } } // 记录异常释放 } ``` 二、堆内存统计法(实时监控) ```c // 使用FreeRTOS内存统计接口示例 #include <FreeRTOS.h> #include <task.h> void check_heap() { size_t free_heap = xPortGetFreeHeapSize(); size_t min_heap = xPortGetMinimumEverFreeHeapSize(); printf("当前可用堆: %d字节, 历史最低: %d字节\n", free_heap, min_heap); if(free_heap < (min_heap * 0.9)) { // 触发泄漏警报 } } ``` 三、MTrace实战步骤(GLIBC环境) 1. 代码植入: ```c #include <mcheck.h> int main() { mtrace(); // 开启内存跟踪 // 业务代码... muntrace(); // 关闭跟踪 return 0; } ``` 2. 运行配置: ```bash export MALLOC_TRACE=memleak.log ./embedded_app ``` 3. 日志分析: ```bash mtrace ./embedded_app $MALLOC_TRACE ``` 四、Segger SystemView工具链集成 1. 植入监控代码: ```c #include "SEGGER_SYSVIEW.h" void* custom_malloc(size_t size) { void* p = malloc(size); SEGGER_SYSVIEW_Log("[MEM] Alloc %p (%d bytes)", p, size); return p; } void custom_free(void* p) { SEGGER_SYSVIEW_Log("[MEM] Free %p", p); free(p); } ``` 2. 使用J-Link调试器捕获实时内存事件 3. 通过SystemView分析时序图中的内存分配/释放匹配性 五、ARM DS-5 Streamline实战流程 1. 配置DS-5的Linux版Streamline 2. 连接目标板(Cortex-M系列示例) ```bash # 启动gator守护进程 ./gatord -p 8080 ``` 3. 添加内存监控计数器: - 内存池剩余量 - 堆碎片化指数 - 分配峰值记录 4. 压力测试后生成内存趋势图,定位异常增长点 选择策略建议: - 开发阶段:内存分配追踪法 + SystemView实时监控 - 测试验证:MTrace完整扫描 + DS-5长期趋势分析 - 量产诊断:固化精简版内存统计模块,通过诊断接口输出 关键指标监控阈值设置示例: ```c #define MEM_LEAK_THRESHOLD 5% // 连续10次采样内存下降超阈值即报警 #define FRAGMENTATION_LIMIT 30% // 堆碎片超过30%触发整理 ``` 通过组合使用这些方法,可在不显著增加资源占用的前提下(典型开销<3% CPU利用率),实现嵌入式环境下的高效内存泄漏检测。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值