以下介绍常用的内存使用情况查询 API,如果想了解更多,请参考 堆内存分配。
在正常编译烧录示例的基础上加入了以下代码来打印空闲堆内存:
printf("free_heap_size = %d\n", esp_get_free_heap_size());
你可以分别在需要检测内存使用情况的 API 前后添加此 API,如刚进入 app_main() 函数时、完成 Wi-Fi 或 BLE 初始化时和 app_main() 函数结束时加上上述代码来打印查看空闲堆内存。比如使用以下代码来检测 wifi_init_sta()
的内存使用情况:
printf("before init wifi : free_heap_size = %d\n", esp_get_free_heap_size());
wifi_init_sta();
printf("after init wifi : free_heap_size = %d\n", esp_get_free_heap_size());
以下是对应 log:
before init wifi : free_heap_size = 270848
I (596) wifi:wifi driver task: 3ffc1d30, prio:23, stack:6656, core=0
I (596) system_api: Base MAC address is not set
I (596) system_api: read default base MAC address from EFUSE
I (626) wifi:wifi firmware version: 10db11f
I (626) wifi:wifi certification version: v7.0
I (626) wifi:config NVS flash: enabled
I (626) wifi:config nano formating: disabled
I (626) wifi:Init data frame dynamic rx buffer num: 32
I (636) wifi:Init management frame dynamic rx buffer num: 32
I (636) wifi:Init management short buffer num: 32
I (646) wifi:Init dynamic tx buffer num: 32
I (646) wifi:Init static rx buffer size: 1600
I (646) wifi:Init static rx buffer num: 10
I (656) wifi:Init dynamic rx buffer num: 32
I (766) phy: phy_version: 4182, f1ba940, Jun 4 2020, 19:40:07, 0, 0
I (766) wifi:mode : sta (30:ae:a4:80:01:c4)
I (766) wifi station: wifi_init_sta finished.
I (896) wifi:new:<6,0>, old:<1,0>, ap:<255,255>, sta:<6,0>, prof:13
I (896) wifi:state: init -> auth (b0)
I (896) wifi:state: auth -> assoc (0)
I (906) wifi:state: assoc -> run (10)
I (1226) wifi:connected with zztest, aid = 5, channel 6, BW20, bssid = 20:6b:e7:34:f5:36
I (1226) wifi:security: WPA2-PSK, phy: bgn, rssi: -21
I (1226) wifi:pm start, type: 1
I (1276) wifi:AP's beacon interval = 102400 us, DTIM period = 1
I (2586) esp_netif_handlers: sta ip: 192.168.1.100, mask: 255.255.255.0, gw: 192.168.1.1
I (2586) wifi station: got ip:192.168.1.100
I (2586) wifi station: connected to ap SSID:zztest password:espressif
after init wifi : free_heap_size = 232000
可以清楚的看到 log 首尾分别打印了空闲内存,如果不存在其他干扰的情况下,它们的差值即为 wifi_init_sta()
使用的内存。
如何使用 esp-idf 创建与编译示例请查看 ESP-IDF 编程指南。
注:你也可以使用 esp_get_minimum_free_heap_size() 来检测最小空闲内存。
heap_caps_print_heap_info()` 能打印具有给定功能的所有内存的列表。在正常编译烧录示例的基础上加入了以下代码来打印给定功能的所有内存的列表:
printf("heap_caps metadata test\n");
heap_caps_print_heap_info(MALLOC_CAP_8BIT);
heap_caps_print_heap_info(MALLOC_CAP_32BIT);
你可以在需要检测给定功能的内存使用情况的地方使用此 API。比如在 station 示例里的 app_main 函数最后加上上述三行后,log 如下:
heap_caps metadata test
Heap summary for capabilities 0x00000004:
At 0x3ffae6e0 len 6432 free 0 allocated 6292 min_free 0
largest_free_block 0 alloc_blocks 27 free_blocks 0 total_blocks 27
At 0x3ffb9308 len 158968 free 103012 allocated 55256 min_free 100064
largest_free_block 102720 alloc_blocks 159 free_blocks 8 total_blocks 167
At 0x3ffe0440 len 15072 free 15036 allocated 0 min_free 15036
largest_free_block 15036 alloc_blocks 0 free_blocks 1 total_blocks 1
At 0x3ffe4350 len 113840 free 113804 allocated 0 min_free 113804
largest_free_block 113804 alloc_blocks 0 free_blocks 1 total_blocks 1
Totals:
free 231852 allocated 61548 min_free 228904 largest_free_block 113804
Heap summary for capabilities 0x00000002:
At 0x3ffae6e0 len 6432 free 0 allocated 6292 min_free 0
largest_free_block 0 alloc_blocks 27 free_blocks 0 total_blocks 27
At 0x3ffb9308 len 158968 free 103012 allocated 55256 min_free 100064
largest_free_block 102720 alloc_blocks 159 free_blocks 8 total_blocks 167
At 0x3ffe0440 len 15072 free 15036 allocated 0 min_free 15036
largest_free_block 15036 alloc_blocks 0 free_blocks 1 total_blocks 1
At 0x3ffe4350 len 113840 free 113804 allocated 0 min_free 113804
largest_free_block 113804 alloc_blocks 0 free_blocks 1 total_blocks 1
At 0x40095d54 len 41644 free 41608 allocated 0 min_free 41600
largest_free_block 41608 alloc_blocks 0 free_blocks 1 total_blocks 1
Totals:
free 273460 allocated 61548 min_free 270504 largest_free_block 113804
可以看到此 API 清楚的打印了具有给定功能的所有内存的列表。
注:你也可以使用 heap_caps_get_minimum_free_size() 来获得具有给定功能的所有区域的最小总可用内存。
使用 make size-components
查看生成的固件内存使用情况, 查看你的模块中是否存在较大的全局变量
total sizes:
DRAM .data size: 13272 bytes
DRAM .bss size: 34024 bytes
Used static DRAM: 47296 bytes ( 77284 available, 38.0% used)
Used static IRAM: 96352 bytes ( 34720 available, 73.5% used)
Flash code: 1101719 bytes
Flash rodata: 267772 bytes
Total image size:~1479115 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
Archive File DRAM .data & .bss IRAM Flash code & rodata Total
libbt.a 325 2338 460 155773 53596 212492
libmesh.a 186 3636 0 161096 38471 203389
libnet80211.a 924 8906 3782 111740 13750 139102
libmbedtls.a 100 268 30 108099 19263 127760
liblwip.a 19 4172 0 89540 16876 110607
libc.a 0 20 0 85809 6516 92345
...
...
DRAM: 链接器将非常量静态数据和未初始化数据放入 0x3FFB0000 — 0x3FFF0000 这 256kB 的区域。注意,如果使用蓝牙堆栈,此区域会减少 64kB(通过将起始地址移至 0x3FFC0000 )。如果使用了内存跟踪的功能,该区域的长度还要减少 16kB 或者 32kB。放置静态数据后,留在此区域中的剩余空间都用作运行时堆。常量数据也可以放在 DRAM 中,需要使用 DRAM_ATTR 宏来声明。
IRAM: ESP-IDF 将内部 SRAM0 区域(在技术参考手册中有定义)的一部分分配为指令 RAM。除了开始的 64kB 用作 PRO CPU 和 APP CPU 的高速缓存外,剩余内存区域(从 0x40080000 至 0x400A0000 )被用来存储应用程序中部分需要在RAM中运行的代码。
注: 内存布局说明
同时你可以使用 FreeRTOS 打印系统当前的任务列表,任务状态优先级,使用率等信息。使用示例如下:
void app_main()
{
xTaskCreate(test_task, "test_task", 4096, NULL, 6, NULL);
static char InfoBuffer[512] = {0};
while (1) {
vTaskList((char *) &InfoBuffer);
printf("任务名 任务状态 优先级 剩余栈 任务序号\r\n");
printf("\r\n%s\r\n", InfoBuffer);
vTaskDelay(2000 / portTICK_PERIOD_MS);
}
}
对应 log 打印如下:
任务名 任务状态 优先级 剩余栈 任务序号
main R 1 2996 2
IDLE0 R 0 1232 3
test_task B 6 3460 5
Tmr Svc B 1 2684 4
esp_timer B 22 3632 1
这样就可以查看每个 task 的相关信息了。