ESP 内存占用优化
备注
虽然该文档主要针对 ESP32-C2 芯片的内存优化,但其中的大部分优化项适用于所有 ESP 系列芯片,因此在其他 ESP 芯片上进行内存优化时也可参考此文档。
引言
ESP32-C2 芯片可用物理内存为 256 KB,但是实际测试时,按照 IDF 指导文档编译 BLE + Wi-Fi 的共存示例 bleprph_wifi_coex,运行起来之后的剩余内存就只有 24 KB,这基本上很难在 ESP32-C2 上面开发复杂的应用。
造成这种问题的原因是 ESP32-C2 默认配置是性能优先,很多基础组件都编译到 IRAM 以提高运行速度。但是对于 ESP32-C2 这种低成本方案来而言,大部分场景只需要简单的控制操作,针对这样的应用,用户可以大幅度优化内存,在深度优化的情况下最多可以优化出超过 100 KB 的内存。
本文在 ESP-IDF release/v5.5 分支上对 ESP32-C2 的内存进行了优化,并说明这些优化对于内存的影响以及如何使能这些优化项。
警告
本文档所列的部分内存占用优化方法可能会降低系统性能及稳定性,在进行内存占用优化后应当进行充分的性能与稳定性测试,以确保满足应用需求。
获取当前剩余内存
在进行内存优化前,需要首先了解当前的内存占用情况,对于静态内存占用,可以在编译后使用 idf.py size 与 idf.py size-components 命令对内存进行统计。
对于运行时内存占用,通过 esp_get_free_heap_size() 与 esp_get_minimum_free_heap_size() 函数可以分别获得系统当前的剩余内存和自系统启动以来的最小剩余堆内存大小。具体可参考 ESP-IDF 堆内存说明 。
ESP32-C2 内存测试结果
下列数据是 ESP32-C2 在 tag v5.5-beta1 使用 ESP-IDF 示例在默认配置(即使用 idf.py set-target esp32c2 后的缺省配置),以及通过各种配置项优化内存后的剩余内存比较。
测试场景说明
station : 在 GOT IP 事件触发之后打印剩余内存
WiFi station + 1TLS(MQTTS) : 使用 mqtt/ssl 示例,在 MQTT_EVENT_DATA 事件触发后打印剩余内存
bleprph_wifi_coex : 在 WiFi GOT_IP 事件触发之后初始化 nimble 并开启 BLE 广播,打印剩余内存
bleprph_wifi_coex + mbedtls + power_save : 在 bleprph_wifi_coex 的基础上集成 https_mbedtls 和 power_save 功能,在连接到 https 服务器后打印剩余内存
默认配置内存占用对比
测试用例 |
默认配置 (KB) |
优化配置 (KB) |
|---|---|---|
station |
95 |
169 |
WiFi station + 1TLS(MQTTS) |
55 |
152 |
bleprph_wifi_coex |
24 |
125 |
bleprph_wifi_coex + mbedtls + power_save |
内存不足 |
115 |
备注
本文档仅针对 ESP32-C2 内存优化过程与效果进行说明。更多关于不同芯片、不同场景下的内存使用情况统计,请参考 内存使用情况对比。
优化策略
本文的优化策略基于一个自己实现的测试用例 bleprph_wifi_coex + mbedtls + power_save demo ,包含了 Wi-Fi + BLE + HTTPS + power save 自动休眠这些常用场景。具体 demo 和内存策略配置项可以参考 此链接。在未执行任何优化时,会因为执行时内存不足触发复位。
优化方案对比
优化方案 |
v5.4.1 (bytes) |
v5.5 (bytes) |
说明 |
|---|---|---|---|
无优化 |
内存不足 |
内存不足 |
使用 idf.py set-target esp32c2 后的缺省配置 |
基础优化 |
62840 |
60212 |
按照内存优化章节对配置项进行优化 |
进阶优化 |
91976 |
90576 |
在基础优化上继续优化,适用于 v5.4.x 及之前版本 |
v5.5 深度优化 |
118096 |
利用 v5.5 新特性进行深度优化 |
备注
其中:
无优化:是使用
idf.py set-target esp32c2后的默认配置,仅保证功能可用(如使能蓝牙、PM 等基础配置),未对内存使用做任何专门优化。基础优化:完全按照 ESP-IDF 内存优化章节 所述进行配置选项优化,涉及将各类函数从 IRAM 放置到 flash,减小 WiFi buffer 并优化 mbedtls 配置等。
进阶优化:基于基础优化,结合文档进一步深度优化,尤其适用于 v5.4.x 及之前版本。此时内存使用数据代表这些版本下”最终优化”结果。
v5.5 深度优化:在进阶优化基础上继续优化,但只针对 v5.5 及之后 ESP-IDF 版本。该优化通过利用新特性(如 flash suspend)让更多代码可以放到 flash,从而释放 IRAM,最大程度减小内存占用。
基础优化
ESP-IDF 编程指南提供了一系列 内存优化 的方法,主要包括 IRAM 优化和堆内存优化,IRAM 优化主要将 FreeRTOS、Wi-Fi、heap 等组件的函数放到 flash;堆内存优化主要减少 Wi-Fi、lwip 等组件申请的静态内存数量。通过这些配置项优化(参考 sdkconfig.defaults.opt.1),可以在所有功能执行完之后将可用内存增加到 62 KB。
进阶优化
在基础优化基础上,继续优化,主要包含如下:
使能 CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY
在使能
CONFIG_SPI_FLASH_AUTO_SUSPEND后,通过使能CONFIG_BT_CTRL_RUN_IN_FLASH_ONLY可以把蓝牙 controller 的代码将会全部放置在 flash,这将会再释放约 20 KB 的内存空间。使能编译优化选项
CONFIG_COMPILER_OPTIMIZATION_SIZECONFIG_COMPILER_SAVE_RESTORE_LIBCALLS
这几个编译优化可以继续释放约 8 KB 的内存空间。
在上述配置(基础优化+进阶优化)全部使能后(具体的配置项可以参考 sdkconfig.defaults.opt.2),可用内存增加到 90 KB。
v5.5 深度优化
在 ESP-IDF v5.5 版本,我们对 IRAM 占用进行了深度优化,可以将大部分 IRAM 函数放置在 flash,尤其是在使能 CONFIG_SPI_FLASH_AUTO_SUSPEND 这个配置时。有关所有此类配置的详细列表,请参见 sdkconfig.flash_auto_suspend_iram_reduction。
全部使能这些优化项后(具体的配置项可以参考 sdkconfig.defaults.opt.3),相对于 v5.4.2 版本可以再节省 20 KB 内存。
其中 v5.5 连上 HTTPS 服务器后可用内存可以达到 118 KB,其中 IRAM 的 .text 段占用 10050 Bytes。
而基于 v5.4.2 版本测试,相同的优化配置,连上 HTTPS 服务器后可用内存为 95 KB,其中 IRAM 的 .text 段占用 31206 Bytes。
IRAM text 段对比
使用 idf.py size 命令获取到的 IRAM .text 段内存消耗数据如下:
优化方案 |
v5.4.1 (bytes) |
v5.5 (bytes) |
|---|---|---|
无优化 |
93592 |
100616 |
基础优化 |
56384 |
60088 |
进阶优化 |
36130 |
35912 |
v5.5 深度优化 |
9742 |
其他芯片使用
虽然内存优化主要针对 ESP32-C2 芯片,但是其他新的芯片比如 ESP32-C61、ESP32-C5 同样可以优化,在默认配置项的基础上,可以增加约 80 KB 左右的内存。