程序的段的存储方式与存储区域大小要求
程序的存储和运行涉及 ROM(Flash/非易失性存储器) 和 RAM(易失性存储器) 的分配,不同段在存储和运行时具有不同的特性。以下是详细的分类和计算方式:
1. 程序文件的存储方式
程序在 编译后生成的二进制文件(如 .bin/.hex) 按照以下方式存储在 ROM(Flash) 中:
段类型 | 存储位置 | 说明 |
---|---|---|
Code段 | ROM | 存储程序的可执行代码(机器指令) |
RO_data段 | ROM | 存储只读数据(如 const 常量、字符串常量) |
RW_data段 | ROM | 存储已初始化且非零的全局/静态变量(初始值) |
ZI_data段 | 不存储 | 仅记录大小,运行时在 RAM 中初始化为零 |
关键点:
- ZI_data段 不会占用 ROM 空间,仅记录其大小,由启动代码在 RAM 中初始化为零。
- RW_data段 的初始值存储在 ROM 中,但运行时会被拷贝到 RAM(因为 RAM 可读写,而 ROM 不可写)。
2. 程序运行时的内存布局
程序运行时,内存(RAM)会被划分为以下部分:
段类型 | 存储位置 | 说明 |
---|---|---|
Code段 | ROM 或 RAM | 通常直接从 ROM 执行,但某些系统可加载到 RAM(如 XIP 或加速执行) |
RO_data段 | ROM 或 RAM | 通常只读,可直接从 ROM 访问,但某些情况会加载到 RAM |
RW_data段 | RAM | 从 ROM 拷贝初始值到 RAM,运行时可修改 |
ZI_data段 | RAM | 由启动代码初始化为零 |
堆(Heap) | RAM | 动态内存分配(malloc/free ) |
栈(Stack) | RAM | 存储局部变量、函数调用信息 |
关键点:
- RW_data段 必须加载到 RAM,因为 ROM 不可写。
- ZI_data段 在 RAM 中分配并清零,不占用 ROM 空间。
- 堆和栈 在运行时动态增长,不占用 ROM 空间,但必须预留足够的 RAM。
3. 存储区域的大小计算
(1) ROM(Flash)大小计算
ROM 存储的是 程序文件,其大小由以下部分组成:
ROM 大小=Code段+RO_data段+RW_data段(初始值)
\text{ROM 大小} = \text{Code段} + \text{RO\_data段} + \text{RW\_data段(初始值)}
ROM 大小=Code段+RO_data段+RW_data段(初始值)
- ZI_data段不占用 ROM,仅记录大小。
- RW_data段 的初始值存储在 ROM 中,但运行时会被拷贝到 RAM。
(2) RAM 大小计算
RAM 存储的是 运行时数据,其最小需求为:
RAM 最小需求=RW_data段+ZI_data段
\text{RAM 最小需求} = \text{RW\_data段} + \text{ZI\_data段}
RAM 最小需求=RW_data段+ZI_data段
但实际 RAM 需求 必须更大,因为:
- 堆(Heap):动态内存分配(
malloc
/free
)需要额外空间。 - 栈(Stack):函数调用、局部变量、中断处理等需要栈空间。
实际 RAM 需求:
实际 RAM 需求=RW_data段+ZI_data段+堆大小+栈大小
\text{实际 RAM 需求} = \text{RW\_data段} + \text{ZI\_data段} + \text{堆大小} + \text{栈大小}
实际 RAM 需求=RW_data段+ZI_data段+堆大小+栈大小
示例:
- 如果
RW_data = 2KB
,ZI_data = 4KB
,堆预留1KB
,栈预留1KB
:
最小 RAM=2+4=6KB实际 RAM=2+4+1+1=8KB \text{最小 RAM} = 2 + 4 = 6KB \\ \text{实际 RAM} = 2 + 4 + 1 + 1 = 8KB 最小 RAM=2+4=6KB实际 RAM=2+4+1+1=8KB
4. 启动方式对存储的影响
程序运行时,代码和数据可以有不同的加载方式:
-
直接从 ROM 执行(XIP, eXecute In Place)
- Code段 和 RO_data段 直接从 ROM 读取,不占用 RAM。
- RW_data段 从 ROM 拷贝到 RAM。
- ZI_data段 在 RAM 中初始化为零。
- 优点:节省 RAM,适用于 RAM 较小的嵌入式系统。
- 缺点:ROM 访问速度可能比 RAM 慢。
-
全部加载到 RAM 执行
- Code段、RO_data段、RW_data段 全部从 ROM 拷贝到 RAM。
- ZI_data段 在 RAM 中初始化为零。
- 优点:执行速度更快(RAM 访问快)。
- 缺点:占用大量 RAM,适用于 RAM 较大的系统(如 Linux 应用)。
5. 总结
分类 | ROM(Flash) | RAM |
---|---|---|
Code段 | ✅ 存储 | ❌(除非加载到 RAM 执行) |
RO_data段 | ✅ 存储 | ❌(除非加载到 RAM 执行) |
RW_data段 | ✅ 存储初始值 | ✅ 运行时加载 |
ZI_data段 | ❌ 不存储 | ✅ 运行时初始化为零 |
堆(Heap) | ❌ 不存储 | ✅ 动态分配 |
栈(Stack) | ❌ 不存储 | ✅ 运行时使用 |
存储大小计算:
- ROM 大小 =
Code段 + RO_data段 + RW_data段(初始值)
- RAM 最小需求 =
RW_data段 + ZI_data段
- 实际 RAM 需求 =
RW_data段 + ZI_data段 + 堆 + 栈
适用场景:
- 嵌入式系统(RAM 小):直接从 ROM 执行(XIP)。
- 高性能系统(RAM 大):全部加载到 RAM 执行。
这样,你可以根据目标设备的资源情况(ROM/RAM 大小)合理规划内存布局。