在片内RAM中,常常要指定一个专门的区域来存放某些特别的数据
它遵循顺序存取和后进先出(LIFO/FILO)的原则,这个RAM区叫堆栈。
其实堆栈就是单片机中的一些存储单元,这些存储单元被指定保存一些特殊信息,比如地址(保护断点)和数据(保护现场)。
1、这些存储单元中的内容都是程序执行过程中被中断打断时,事故现场的一些相关参数。如果不保存这些参数,单片机执行完中断函数后就无法回到主程序继续执行了。
2、这些存储单元的地址被记在了一个叫做堆栈指针(SP)的地方。
3、栈是从高到低分配,堆是从低到高分配。
我们一般说的堆栈指的栈。堆栈又分硬堆栈和软堆栈,硬堆栈即SP,从片内RAM的顶部向下生长。软堆栈在硬堆栈跟全局变量区之间的空间,C51函数调用通过R0-R7和栈来实现。
1)子程序调用和中断服务时CPU自动将当前PC值压栈保存,返回时自
动将PC值弹栈。
2)保护现场/恢复现场
3)数据传输
程序内存可以分为几个区,栈区(stack),堆区(Heap),全局区(static),文字常亮区,程序代码区。
//main.cpp
int a = 0; //全局初始化区
int a = 0; //全局初始化区
char *p1; //全局未初始化区
main() {
int b; //栈
char s[] = "abc"; //栈
char *p2; //栈
char *p3 = "123456"; //123456\0在常量区,p3在栈上。
static int c = 0; //全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
//分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); //123456\0放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
和栈的第一个区别就是申请方式不同:栈(英文名称是stack)是系统自动分配空间的,例如我们定义一个 char a;系统会自动在栈上为其开辟空间。而堆(英文名称是heap)则是程序员根据需要自己申请的空间,例如malloc(10);开辟十个字节的空间。由于栈上的空间是自动分配自动回收的,所以栈上的数据的生存周期只是在函数的运行过程中,运行后就释放掉,不可以再访问。而堆上的数据只要程序员不释放空间,就一直可以访问到,不过缺点是一旦忘记释放会造成内存泄露。
在MDK编译环境下,可在map文件的"Memory Map of the image"–>"Execution Region RW_IRAM1"内容中查看程序的RAM占用及分配情况,如下:
Code
:程序代码
RO-data
:const常量和指令
RW-data
:初始化值不为0的全局变量
ZI-data
:未初始化的全局变量 或 初始化值为0的全局变量
RO Size = Code + RO Data 表示程序运行时占用的FLASH大小
RW Size = RW Data + ZI Data 表示占用RAM大小
ROM Size = Code + RO Data + RW Data 表示烧写程序后占用的FLASH大小
一个由C/C ++编译的程序占用的内存可分为以下几个部分:
栈(stack)
:由编译器自动分配释放,存放函数的参数值,局部变量的值等。
堆(heap)
:存放程序运行中被动态分配的内存,一般由程序员分配释放,若程序员不释放,程序结束时可能由OS回收。
bss段
:通常是指用来存放程序中未初始化的全局变量的一块内存区域,存放ZI-data数据
data段
:通常是指用来存放程序中已初始化的全局变量的一块内存区域,存放RW-data数据
文字常量区(const)
:常量字符串就是放在这里的。
程序代码区 (code)
: 存放函数体的二进制代码
STM32的堆栈就是存放在片上静态SRAM中的.
地址分配可以见Keil的编译map文件的"Memory Map of the image"
可见堆的地址为0x20000a08,大小为0x200,栈的地址为 0x20000c08,大小为0x400,可推算栈顶地址为:0x20000c08 + 0x400 = 0x20001008。而程序在刚运行的时候,主堆栈指针MSP指向的是程序所占用内存的最高地址,也就是栈的栈顶地址MSP,也就是中断向量表前四个字节存储的值。