内存模型基础

MCU 程序编译后生成可执行文件(.elf),烧录在Flash(非易失,断电保存);

运行时,变量加载到 RAM(易失,上电使用)。

程序被划分三大核心段:text、data、BSS

1. .text 代码段

✅ 存放:程序代码(编译后的机器码)、常量字符串、const 常量

  • 所有函数代码 main()、中断函数、各个子函数
  • const char *str = "hello"; 字符串字面量
  • const int a = 100; 只读常量

📍 存储位置:Flash

只读,运行不会修改。单片机不能写入 text 段,尝试修改会 HardFault。

示例代码:

const char msg[] = "test"; // 常量放text
void func(void)            // 函数代码 text段
{

}

2. .data 数据段(初始化全局变量段)

✅ 存放:全局 / 静态变量,并且手动赋予初始值

int g_val = 10;        // 全局初始化变量 → .data
static int s_num = 5;  // static初始化变量 → .data

📍运行机制: 上电启动时,启动文件(startup.s)自动把 Flash 上这份初始值拷贝到 RAM,之后程序在 RAM 读写。 📍位置:原始数据存 Flash,运行副本在 RAM。

⚠️ 重点:必须有显式初始值!

3. .bss 段(Block Started by Symbol)未初始化段

✅ 存放:全局、static 静态变量,没有写初始值(默认 = 0)

int g_buffer[1024];     // 无初始化 → BSS
static int stat_var;    // 无初始化 → BSS

📍关键特性: 为了节省 Flash 空间:elf 文件里不保存一堆 0,只记录需要占用多大内存。 上电后启动代码直接在 RAM 把整片内存全部清零。

👉巨大优势:大数组定义成全局无初始化,不会占用 Flash! 如果你写 int buf[1024]={0}; 部分编译器依然归类 BSS; 如果你写 int buf[1024]={1}; 则进入.data,初始数据占用 Flash。

快速区分对照表

段名存放内容存储特点
.text函数代码(编译后的机器码)、const 常量、字符串Flash,只读
.data全局 /static 带初始值变量Flash 存初始值,运行拷贝到 RAM
.bss全局 /static 无初始化变量仅占用 RAM,不占用 Flash

❗高频嵌入式坑点

  1. 局部变量不在这三段! 函数内部 int a; 局部变量 = 栈 (stack),不属于 text/data/bss,运行时临时分配。

  2. 不要在函数内定义超大数组

void test(){
    int big[2048]; // 栈!极易栈溢出死机
}

解决:放到全局 → 进入 BSS,使用 RAM 堆之外的空间。

  1. BSS 大小可以在 map 文件查看 编译输出 .map 文件,搜索 bss、data,用来评估 RAM 占用,排查内存溢出。

上电完整启动流程(Startup.s 做的事)

  1. 从 Flash 复制 .data 段数据到 RAM
  2. 将 RAM 中 .bss 整块内存清零
  3. 调用 main() 开始执行

一句极简总结背诵

  • text:代码常量放 Flash
  • data:有初值全局变量,Flash 存模板,拷贝进 RAM
  • bss:无初值全局变量,只占 RAM,上电清零,不占 Flash

更多推荐