STM32堆栈的大小及内存四(五)区的分析
1、设置堆栈空间的大小
1.1、STM32堆栈空间大小
一般在编程时,我们都不需要考虑堆栈空间的大小,因为在启动文件中都对堆栈空间的大小进行了设置。
1.1.1、直接修改启动文件
如以下截取stm32启动文件部分汇编代码,Stack栈的大小为:0x400(1024Byte),Heap堆的大小为:0x200(512Byte)。
; Amount of memory (in bytes) allocated for Stack
; Tailor this value to your application needs
; <h> Stack Configuration
; <o> Stack Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Stack_Size EQU 0x400
AREA STACK, NOINIT, READWRITE, ALIGN=3
Stack_Mem SPACE Stack_Size
__initial_sp
; <h> Heap Configuration
; <o> Heap Size (in Bytes) <0x0-0xFFFFFFFF:8>
; </h>
Heap_Size EQU 0x200
AREA HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem SPACE Heap_Size
__heap_limit
这也是为什么一个空的的工程编译后,RAM的空间也占用了1.6K的原因,因为堆栈的空间均分配在RAM中。可以在map文件中查看具体占用大小
1.1.2、修改keil Configuration进行设置
如下图所示,可以在打开启动文件页面后,点击Configuration Wizard,可在Option的设置框中设置堆栈空间的大小
1.2、堆栈的分析
1.2.1、堆栈的溢出
若局部变量较多、定义的数据长度,加一起的空间大于**栈(Stack)**的空间,则会导致栈溢出,程序运行结果与预期的不符或程序跑飞。这时需要手动的调整栈的大小,来复合我们的需求
若使用了malloc动态分配内存空间时,大于设置的**堆(Heap)**的空间。会导致溢出,需要调整堆的大小
1.2.2、堆栈的增长方向
一般堆是由低地址往上(高地址)增长,栈是由高地址向下(低地址)增长。都是连续的,C语言不提供内存保护机制类似的功能,如果一直堆一直增长,栈一直申请,然后就会导致栈溢出,程序崩溃
1.2.3、堆栈的首地址
一般堆栈的起始地址是不固定的,是根据用户定义的变量的数目和大小决定的,是编译器自动分配的,内存首先存放/开辟全局变量区域,然后开辟栈区最后开辟堆区
栈首地址=全局区域大小+栈大小(Stack_Size)
1.2.4、堆栈的区别
-
存储的内容:
- 栈存局部变量、函数参数等
- 堆存储使用 new、malloc 申请 的变量等
-
申请的方式:
- 栈内存由系统分配、释放
- 堆内存由自己申请、释放
- 申请后系统的响应:(带操作系统的环境)
- 栈——只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出
- 堆——首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申 请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空 闲结点链表 中删除,并将该结点的空间分配给程序
-
申请大小的限制:
- 单片机一般堆栈大小都是固定
- 有操作系统情况下,堆的大小可以随意增长,收到硬件的显示
-
申请效率的对比:
- 栈由系统自动分配,速度较快
- 堆使用 new、malloc 等分配,较慢
2、内存四(五)区
2.1、内存四区和内存五区的区别
其实内存四区和内存五区所指的东西是一样的,对于内存四区而言,其只是把全局区(静态区)和常量区合并为一个数据区而已,其实内容都是完全一样的
2.1.1、内存四区
栈区、堆区、数据区(全局区(静态区)、常量区)、代码区
2.1.2、内存五区
栈区、堆区、全局区(静态区)、常量区、代码区
2.2、内存四区具体含义
2.2.1、栈区
- 系统自动分配,函数结束自动释放,也可以说由编译器自动分配和释放
- 局部变量、局部常量、函数参数
- 特点:进栈出栈有相应的计算机指令支持,而且分配专门的寄存器存储栈的地址,效率分高,内存空间是连续的,但栈的内存空间有限
2.2.2、堆区
- 使用malloc()/new()申请的内容存储在堆区
- 由程序员手动分配,手动释放,或者程序结束系统回收,不释放就会产生内存泄漏
2.2.3、全局区(静态区)
全局变量、静态变量(全局or局部)
-
全局区分为两个段:
- data段:存储初始化的全局变量、初始化的静态变量
- bss段:存储未初始化的全局变量、未初始化的静态变量
- 调用函数结束不会被销毁
- 其中BSS段会在程序执行前**,将内容全部置为0,**所以未初始化的全局变量和静态变量的值都为0
2.2.4、常量区
- 存放常量,字符串常量和其他常量的存储位置,而且不允许修改
- 程序结束之后由系统释放
2.2.5、代码区
- 要存放程序中的代码(二进制),属性是只读
- 又称text段
2.3、代码示例
int a = 0; //全局初始化区
char *p1; //全局未初始化区
int add(int a; int b)
{
int sum = 0; //栈
static temp; //全局(静态)未始化区
sum = a+b;
return sum;
}
int 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"优化成一块
return 0;
}
参考连接文章来源:https://www.toymoban.com/news/detail-452662.html
https://www.e-learn.cn/topic/3842454
https://blog.csdn.net/u011764302/article/details/103368274文章来源地址https://www.toymoban.com/news/detail-452662.html
到了这里,关于STM32堆栈的大小及内存四(五)区的分析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!