当前位置:   article > 正文

STM32堆栈的大小及内存四(五)区的分析_stm32堆栈空间大小设置

stm32堆栈空间大小设置

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
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

这也是为什么一个空的的工程编译后,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; 
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21

参考连接

https://www.e-learn.cn/topic/3842454
https://blog.csdn.net/u011764302/article/details/103368274

本文内容由网友自发贡献,转载请注明出处:【wpsshop博客】
推荐阅读
相关标签
  

闽ICP备14008679号