STM32堆栈的大小及内存四(五)区的分析

文章目录

  • STM32堆栈的大小及内存四(五)区的分析
  • 1、设置堆栈空间的大小
  • 1.1、STM32堆栈空间大小
  • 1.1.1、直接修改启动文件
  • 1.1.2、修改keil Configuration进行设置
  • 1.2、堆栈的分析
  • 1.2.1、堆栈的溢出
  • 1.2.2、堆栈的增长方向
  • 1.2.3、堆栈的首地址
  • 1.2.4、堆栈的区别
  • 2、内存四(五)区
  • 2.1、内存四区和内存五区的区别
  • 2.1.1、内存四区
  • 2.1.2、内存五区
  • 2.2、内存四区具体含义
  • 2.2.1、栈区
  • 2.2.2、堆区
  • 2.2.3、全局区(静态区)
  • 2.2.4、常量区
  • 2.2.5、代码区
  • 2.3、代码示例
  • 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.e-learn.cn/topic/3842454
    https://blog.csdn.net/u011764302/article/details/103368274

    物联沃分享整理
    物联沃-IOTWORD物联网 » STM32堆栈的大小及内存四(五)区的分析

    发表回复