单片机内存分配管理笔记

本示例使用vscode中cubemx插件,芯片STM32G411CUE6,Flash、RAM分配示意图如下:

一、编译链接阶段静态划分

1. text 段(代码段 / 文本段)

存储内容:程序的机器码(函数体、指令)、const修饰的只读常量(如const int g_val = 10;);

物理映射:唯一映射到Flash(非易失、只读,防止程序代码被意外修改);

核心特性:编译链接后固化,运行时不可修改,占用 Flash 空间,不占用 RAM 空间;

2. rodata 段(只读数据段)

存储内容:字符串常量(如"hello world")、未用const修饰但实际只读的常量;

物理映射:映射到Flash(只读,非易失);

与 text 段的关系:text 段偏 "执行指令",rodata 段偏 "只读数据",本质都是 Flash 中的只读内容。

3. data 段(已初始化数据段)

存储内容:显式赋初始值的全局变量、显式赋初始值的静态变量(static修饰),如int g_init = 10;static char s_buf = 'a';

物理映射:双占用特性------ 初始值存 Flash(烧录时固化),运行时变量本体存 RAM(可读写);

核心特性:程序上电启动后,启动文件会自动将 Flash 中的初始值拷贝到 RAM的 data 段区域,完成变量初始化;

与 BSS 段的核心区别:都是存全局 / 静态数据、都占 RAM,但 data 段需要 Flash 存初始值,BSS 段不需要。

4. bss 段(未初始化数据段)

存储内容:未显式赋初始值的全局变量、未显式赋初始值的静态变量,如int g_uninit;static long s_uninit;

物理映射:仅占用 RAM,不占用任何 Flash 空间(核心特性,无初始值可存储,无需烧录);

核心特性:程序上电启动后,启动文件会自动将 bss 段对应的 RAM 区域全部清零(赋 0),因此未初始化的全局 / 静态变量默认值一定是 0;

二、程序运行时的RAM 动态内存区域

1. 栈区(Stack)------ 自动管理

存储内容:局部变量(函数内定义的非 static 变量,如void func(){ int a; })、函数调用的返回地址、函数参数、寄存器临时值;

管理方式:编译器自动分配和释放,函数调用时,局部变量入栈;函数执行结束,局部变量出栈,内存自动回收;

核心特性:① 地址向下生长(从高地址向低地址分配内存);② 有固定大小限制(小心溢出);③ 局部变量默认值随机(不会被清零,与 BSS 段的 "自动清零" 形成鲜明对比);

与 BSS 段的核心区别:

对比维度 栈区 BSS 段
存储数据 局部变量、函数参数 未初始化全局 / 静态变量
管理方式 编译器自动管理 链接器静态分配
生命周期 随函数调用结束消失 整个程序运行周期
初始化方式 无,默认随机值 启动文件自动清零

2. 堆区(Heap)------ 手动管理

存储内容:程序员通过动态内存函数申请的内存,如 C 标准库的malloc()calloc()realloc(),单片机裸机开发中也可自定义堆区申请函数;

管理方式:程序员手动分配和释放------ 申请后必须用free()释放,否则会造成内存泄漏;

核心特性:① 地址向上生长(从低地址向高地址分配内存);② 无固定大小限制(最大为 RAM 中未被其他区域占用的剩余空间);③ 是单片机动态内存分配的唯一方式(如运行时根据需求创建数组、缓冲区);

与 BSS 段的核心区别:BSS 段是静态分配(编译链接时确定大小),堆区是动态分配(运行时确定大小);BSS 段由系统管理,堆区由程序员手动管理。

三、对比表

内存层级 区域名称 存储核心内容 映射 分配阶段 管理方式 初始化方式 生命周期
逻辑段(静态) text 机器码、const 只读常量 Flash 编译链接 链接器 编译固化,不可修改 整个程序运行期
逻辑段(静态) rodata 字符串常量、只读数据 Flash 编译链接 链接器 编译固化,不可修改 整个程序运行期
逻辑段(静态) data 已初始化全局 / 静态变量 RAM 编译链接 链接器 启动时从 Flash 拷贝到 RAM 整个程序运行期
逻辑段(静态) bss 未初始化全局 / 静态变量 RAM 编译链接 链接器 启动文件自动清零(赋 0) 整个程序运行期
运行时区域(动态) 栈区 局部变量、函数参数、返回地址 RAM 程序运行 编译器自动 无,默认随机值 随函数调用结束
运行时区域(动态) 堆区 动态申请的内存(malloc 等) RAM 程序运行 程序员手动 无,默认随机值(calloc 除外) 手动释放前

四、实践

使用CMake中的辅助工具,可以清晰看到代码编译后的内存分配

data段数据示例(static uint8_t 编译后被归类到RAM data段)

bss数据段示例(未进行初始化或初始化为0的数据被编译归类为RAM bss段,注:STATE_WAIT_START = 0)

text数据段示例(函数SQUARE_Init被编译后归类到Flash text)

rodata数据段示例(const字体数组被编译归类到Flash rodata段)

相关推荐
xlp666hub22 分钟前
Leetcode第五题:用C++解决盛最多水的容器问题
linux·c++·leetcode
得物技术2 小时前
搜索 C++ 引擎回归能力建设:从自测到工程化准出|得物技术
c++·后端·测试
xlp666hub1 天前
Leetcode 第三题:用C++解决最长连续序列
c++·leetcode
会员源码网1 天前
构造函数抛出异常:C++对象部分初始化的陷阱与应对策略
c++
xlp666hub1 天前
Leetcode第二题:用 C++ 解决字母异位词分组
c++·leetcode
不想写代码的星星1 天前
static 关键字:从 C 到 C++,一篇文章彻底搞懂它的“七十二变”
c++
xlp666hub2 天前
Leetcode第一题:用C++解决两数之和问题
c++·leetcode
不想写代码的星星2 天前
C++继承、组合、聚合:选错了是屎山,选对了是神器
c++
不想写代码的星星3 天前
std::function 详解:用法、原理与现代 C++ 最佳实践
c++
齐生14 天前
iOS 知识点 - 渲染机制、动画、卡顿小集合
笔记