目录
一、堆(Heap)
堆是程序运行时可以动态申请、使用、释放的内存区域(区别于栈的自动分配释放)。比如你需要临时存一组数据,但不知道提前需要多大空间,就可以从堆里 “借” 一块内存,用完后 “还” 回去。

堆的本质是一块连续的内存区域,这里用heap_buff[1024]来模拟一块大小为1024字节的堆区
在主函数里my_malloc(100)申请100字节,然后buff指针操作,存了26字节
使用完后需使用free释放掉,防止内存泄漏。
二、栈(Stack)
1.局部变量在栈中如何被分配
两个关键指针
栈顶指针(ESP/RSP):指向最顶端,栈是从高地址往低地址生长的,所以 ESP/RSP 会随着数据压栈减小,弹栈增大
帧指针(基址指针)(EBP/RBP):指向当前函数栈帧的底部(固定住栈帧)
函数调用时,局部变量分配的过程
void test(int a, int b) {
int x = 10; // 局部变量1
char y = 'c'; // 局部变量2
int z = 20; // 局部变量3
}
int main() {
test(3, 5); // 调用test函数,传入参数3和5
return 0;
}
当test(3,5)被调用时:
1.压入函数参数(从右往左)
栈的生长方向是高地址到低地址,所以参数会从右到左压栈不同架构可能有差异,但 x86 是这样)
先压b(地址较高)
再压a(地址较低)
此时栈顶指针(ESP/RSP)指向a(栈顶)
2.压入返回地址
test执行完后要回到main继续执行,所以会把mian中test(3,5)的下一条指令地址压入栈,同时ESP继续减小
3.创建栈帧(压入EBP,更新栈帧的基址)
先把当前main的EBP压入栈;
再把ESP的值赋给EBP,让 EBP 指向当前test函数栈帧的底部
4.分配局部变量
局部变量会在EBP下方(低地址方向)分配空间:
先分int x = 10; 占4字节,地址为 EBP-4
再分配char y = 'c' 占1字节,地址为EBP-5
最后分配int z = 20占4字节,地址为EBP-9
5.函数结束,销毁栈帧
把 ESP 的值恢复到 EBP 的位置
void test() {
int a = 1; // 变量a:先定义(先进栈)
int b = 2; // 变量b:后定义(后进栈)
int c = 3; // 变量c:最后定义(最后进栈)
} // 函数结束,变量释放:c先释放,再b,最后a(后出)
2.为何每个RTOS任务都有自己的栈
RTOS 的多任务,本质是多个 “独立的执行流” 在 CPU 上分时运行(任务 A 跑 1ms,切换到任务 B 跑 1ms),每个任务就像 “独立的小程序”,都需要自己的栈来存,在切换任务时,会把A自己的局部变量、指令地址、寄存器里的值、函数调用的状态储存到自己的栈上,再执行B
如果所有任务共用一个栈,任务 A 刚在栈里存了局部变量x=1,切换到任务 B 后,任务 B 的局部变量会把x=1覆盖掉,等切回任务 A 时,x的值已经被改成任务 B 的数据,程序直接乱套。
RTOS 任务的独立栈,是任务独立性、任务切换连续性、数据隔离性的基础 —— 每个任务靠自己的栈 “保存自己的状态、跑自己的逻辑”,互不干扰,这才是多任务系统能正常工作的核心前提之一。



3577

被折叠的 条评论
为什么被折叠?



