电子说
使用ESP32时如果怀疑存在内存泄漏,第一步是找出程序的哪个部分正在泄漏内存。使用xPortGetFreeHeapSize()、heap_caps_get_free_size()或相关函数来跟踪应用程序生命周期内的内存使用情况。尝试将泄漏缩小到单个函数或函数序列,在这些函数中,可用内存总是减少并且永远不会恢复。
一旦确定了正在泄漏的代码:
·在项目配置菜单中,导航到Component settings -> Heap Memory Debugging -> Heap tracing,选择Standalone选项。
·在程序运行前调用heap_trace_init_standalone() 注册一个可用于记录内存跟踪的缓冲区。
·调用 heap_trace_start()开始记录系统中的所有malloc/free。在你怀疑正在泄漏内存的代码段之前立即调用此方法。
·调用heap_trace_stop()在怀疑代码段完成执行后停止跟踪。
·调用 heap_trace_dump()转储堆跟踪的结果。
示例代码:
#include "esp_heap_trace.h"
#define NUM_RECORDS 100
static heap_trace_record_t trace_record[NUM_RECORDS]; // This buffer must be in internal RAM
...
void app_main()
{
...
ESP_ERROR_CHECK( heap_trace_init_standalone(trace_record, NUM_RECORDS) );
...
}
void some_function()
{
ESP_ERROR_CHECK( heap_trace_start(HEAP_TRACE_LEAKS) );
do_something_you_suspect_is_leaking();
ESP_ERROR_CHECK( heap_trace_stop() );
heap_trace_dump();
...
}
堆跟踪的输出大概这样:
2 allocations trace (100 entry buffer)
32 bytes (@ 0x3ffaf214) allocated CPU 0 ccount 0x2e9b7384 caller 0x400d276d:0x400d27c1
0x400d276d: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:27
0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52
8 bytes (@ 0x3ffaf804) allocated CPU 0 ccount 0x2e9b79c0 caller 0x400d2776:0x400d27c1
0x400d2776: leak_some_memory at /path/to/idf/examples/get-started/blink/main/./blink.c:29
0x400d27c1: blink_task at /path/to/idf/examples/get-started/blink/main/./blink.c:52
40 bytes 'leaked' in trace (2 allocations)
total allocations 2 total frees 0
上面的示例输出是使用IDF监视器自动解码PC地址到它们的源文件和行号。
第一行表示与缓冲区的总大小相比,缓冲区中有多少分配项。
在HEAP_TRACE_LEAKS模式下,对于每个尚未释放的跟踪内存分配,打印一行:
XXbytes
为已分配的字节数@0x...
是从malloc/calloc返回的堆地址。Internal
或PSRAM
是分配内存的一般位置。CPUx
CPU x是分配时正在运行的CPU(0或1)。ccount0x...
是分配模式时的CCOUNT (CPU周期计数)寄存器值。不同于CPU 0和CPU 1。caller0x...
给出调用malloc()/free()的调用堆栈,作为PC地址列表。可以将它们解码为源文件和行号。可以在项目配置菜单中Heap Memory Debugging -> Enable heap tracing -> Heap tracing stack depth配置为每个跟踪项记录的调用堆栈的深度。每个分配最多可以记录10个堆栈帧(默认为2个)。每增加一个堆栈帧,每个heap_trace_record_t记录的内存使用都会增加8个字节。
最后,打印内存泄漏字节的总数(在运行跟踪时已分配但未释放的字节),以及它所表示的总分配数。如果跟踪缓冲区的大小不足以容纳发生的所有分配,则将打印警告。如果看到此警告,应该缩短跟踪周期或增加跟踪缓冲区中的记录数量。
全部0条评论
快来发表一下你的评论吧 !