ESP32内存分布全解析
ESP32内存分布详解
详细解释ESP32的内存分布情况,包括如何判断堆栈空间大小,以及程序、函数、常量、变量的存放位置。
一、ESP32内存区域划分
ESP32的内存结构主要分为以下几类:
1. 片内RAM
- SRAM0:用于IRAM(指令RAM)
- SRAM1:用于IRAM和DRAM
- SRAM2:用于DRAM(数据RAM)
2. 内存区域具体划分
| 区域 | 大小 | 地址范围 | 用途 |
|---|---|---|---|
| IRAM | 192KB | 0x40078000-0x400A0000 | 指令RAM,用于存储需要快速执行的代码 |
| DRAM | 328KB | 0x3FFB0000-0x3FFF0000 | 数据RAM,用于存储数据 |
| DROM | 4MB | 0x3F400000-0x3F800000 | 只读数据,存储常量数据 |
| RTC Fast | 16KB | 0x50000000-0x50003FFF | RTC快速存储器,深度睡眠后必须执行的代码 |
| RTC Slow | 16KB | 0x50004000-0x50007FFF | RTC慢速存储器,深度睡眠后数据保持 |
注意:IRAM和DRAM的地址范围方向是相反的。
二、程序、函数、常量、变量的存放位置
1. 程序/函数
- 默认情况:存储在Flash中(IROM),通过Flash MMU执行
- 需要放入IRAM的情况:
- 中断处理程序(必须使用
ESP_INTR_FLAG_IRAM) - 时序关键代码(减少Flash加载延迟)
- 通过
IRAM_ATTR宏指定:
#include "esp_attr.h" void IRAM_ATTR gpio_isr_handler(void *arg) {// 代码 } - 中断处理程序(必须使用
2. 常量
- 默认情况:存储在DROM(Flash中,0x3F400000-0x3F800000)
- 可放入DRAM的情况(通过
DRAM_ATTR):DRAM_ATTR const char format_string[] = "%p %x";
3. 变量
- .data段:已初始化的全局变量和静态变量,存储在DRAM中
- .bss段:未初始化的全局变量和初始化为0的静态变量,存储在DRAM中
- 局部变量:存储在栈区(DRAM中)
- 动态分配内存:通过
malloc/calloc分配,存储在堆区(DRAM中)
三、如何判断堆栈空间大小
1. 堆空间大小
- 当前剩余堆大小:
uint32_t esp_get_free_heap_size(void); - 最小堆大小(历史最小值):
uint32_t esp_get_minimun_free_heap_size(void);
2. 栈空间大小
-
任务栈剩余大小(高水位线):
UBaseType_t uxTaskGetStackHighWaterMark(TaskHandle_t xTask);返回值表示自任务开始运行以来,任务栈使用的峰值时剩余的栈大小。
-
示例代码:
#include "freertos/FreeRTOS.h" #include "freertos/task.h"void task_function(void *pvParameter) {int stack_left = uxTaskGetStackHighWaterMark(NULL);printf("Stack left: %d bytes\n", stack_left);// 任务执行代码 }
四、ESP32内存分布示意图
+-------------------------+ (高地址)
| IRAM (192KB) | 0x40078000-0x400A0000
| (代码执行区域) |
+-------------------------+
| DROM (4MB) | 0x3F400000-0x3F800000
| (常量数据) |
+-------------------------+
| DRAM (328KB) | 0x3FFB0000-0x3FFF0000
| (数据区域) |
| +---------------------+|
| | 堆 (heap) | (动态内存)
| +---------------------+|
| | 栈 (stack) | (任务栈)
| +---------------------+|
| | .data段 (初始化变量)| (全局变量)
| +---------------------+|
| | .bss段 (未初始化变量)| (全局变量)
| +---------------------+|
+-------------------------+
| RTC Fast (16KB) | 0x50000000-0x50003FFF
| (深度睡眠后必须执行) |
+-------------------------+
| RTC Slow (16KB) | 0x50004000-0x50007FFF
| (深度睡眠后数据保持) |
+-------------------------+ (低地址)
五、注意事项
-
IRAM限制:
- 用于访问IRAM中数据的地址必须是32位对齐的
- 访问的数据大小也必须是32位对齐的
-
DRAM和IRAM的使用:
- IRAM用于需要快速执行的代码(如中断处理程序)
- DRAM用于数据存储(包括堆和栈)
-
堆栈分配:
- 创建任务时需指定栈大小(如
xTaskCreate(task, "task", 4096, NULL, 1, NULL)) - 堆大小在FreeRTOS配置中定义,需合理分配
- 创建任务时需指定栈大小(如
-
深度睡眠:
- 深度睡眠后必须执行的代码需放在RTC Fast memory
- 深度睡眠后需要保持的数据需放在RTC Slow memory
通过以上信息,您可以清晰地了解ESP32的内存分布和如何合理分配资源,避免内存不足导致的系统崩溃。
