【Linux】C程序的储存空间是如何分配(栈,堆,代码段,BSS段,数据段)

程序内存分区

C语言内存分区示意图如下:

在这里插入图片描述

C语言五大内存分区

  • 栈区(stack):

     栈区由编译器自动分配释放,由操作系统自动管理,无须手动管理。
     栈区上的内容只在函数范围内存在,当函数运行结束,这些内容也会自动被销毁。
     栈区按内存地址由高到低方向生长,其最大大小由编译时确定,速度快,但自由性差,最大空间不大。
     栈区是先进后出原则,即先进去的被堵在屋里的最里面,后进去的在门口,释放的时候门口的先出去。
    

    存放内容

     临时创建的局部变量和const定义的局部变量存放在栈区。
     函数调用和返回时,其入口参数和返回值存放在栈区。
    
  • 堆区(heap):

     堆区由程序员分配内存和释放。
     堆区按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定,速度较慢,但自由性大,可用空间大。
    

    调用函数
    用malloc等函数实现动态分布内存。

    void *malloc(size_t);
    

    参数size_t是分配的字节大小。
    返回值是一个void*型的指针,该指针指向分配空间的首地址。
    (void *型指针可以任意转换为其他类型的指针)

    用free函数进行内存释放,否则会造成内存泄漏。

    void free(void * /*ptr*/);
    

    参数是开辟的内存的首地址。

  • 全局/静态存储区:
    存放全局变量和静态变量(包括静态全局变量与静态局部变量),初始化的全局变量和静态局部变量放在一块,未初始化的放在另一块全局区有 .bss段 和 .data段组成,可读可写

  • 文字常量区

     常量在统一运行被创建,常量区的内存是只读的,程序结束后由系统释放。
     字符串、数字等常量存放在常量区。
     const修饰的全局变量存放在常量区。
     程序运行期间,常量区的内容不可以被修改
    
  • 程序代码区:

     存放程序的二进制代码,内存由系统管理
     程序执行代码存放在代码区,其值不能修改(若修改则会出现错误)。
     字符串常量和define定义的常量也有可能存放在代码区
    

可执行程序程序三段-Text段,Date段,Bss段

在这里插入图片描述
一个程序的3个基本段:text段,dtae段,bss段

  • text段:代码段,就是放程序代码的,编译时确定,在内存中被映射为只读,但date段与bss段是可写的
  • date段:存放在编译阶段(而非运行时)就能确定的数据,可读可写。也就是通常所说的静态存储区,赋了初值的全局变量和赋初值的静态变量存放在这个区域,常量也存在这个区域
  • bss段:已经定义但没赋初值的全局变量和静态变量存放在这个区域

两者之间区别

两者之间区别是:代码段,数据段,堆栈段是cpu级别的概念,五大分区属于语言级别的概念,两者是不同的概念。

存储类型关键字定义变量与函数作用域与生命周期

在这里插入图片描述

  • auto变量:函数的局部变量,如果没有声明为static,函数中定义的局部变量全部为auto类型,auto变量包括未加static声明的局部变量和函数的形参。在函数调用时系统会给他们分配存储空间,在函数调用结束后会自动释放这些空间。属于动态存储方式。
  • static变量:用static声明的局部变量在调用结束后不会消失而保存原来的值。static局部变量定义使用后值会存储下来。所以使用static局部变量定义只需要一次赋值。静态局部变量的作用域仅限于所定义的函数。但函数结束后变量的值会保留。直到整个程序运行结束。全局变量从定义开始作用于整个文件直至程序运行结束。
  • register寄存器变量:寄存器变量可以提高c语言的执行效率,即将局部变量的值存入CPU的寄存器中。需要注意的是!!!:1.只有动态存储的变量(自动局部变量和形参)才可以作为寄存器变量来存储,局部静态变量不可以定义为寄存器变量。2.计算机的寄存器数目是有限的,所以不能定义任意多个寄存器变量。
  • extern外部变量:即全局变量的外部表现形式,是在函数外部定义的变量。全局变量的作用域为从定义开始到源文件结束。exten对该变量作外部变量声明,扩展变量作用域。

堆与栈的区别

  1. 申请方式
    stack:栈;由系统自动分配,自动开辟空间
    heap:由程序员自己申请并指明大小,c中malloc,c++中new。如

    p1=(char*)malloc(10);
    p2=(char*)new(10);
    

    但需要注意的是p1,p2本事是在栈中的

  2. 申请后系统的响应
    栈:只要栈的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示栈溢出
    堆:首先操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个大于所申请空间的堆节点,然后将该节点从空闲节点链表中删除,并将该节点的空间分配给程序。另外对于大部分系统,会在这块内存空间中的首地址处记录本次分配的大小,这样代码中的delete语句才能正确的释放本内存空间。另外由于找到的堆节点大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。

  3. 申请大小的限制
    栈:在windows下栈是向低地址扩展的数据结构,是一块连续的内存区域。所以栈的栈顶地址和最大容量是系统预先设定好的。在windows下栈的大小是2M.因此能从栈获得的空间比较小。
    堆:堆是向高地址扩展的数据结构,是不连续的内存区域。这是是由于系统用链表来存储空闲内存地址的,所以是不连续的。而链表的遍历方向是由低地址到高地址。堆得大小受限于计算机系统中有效的虚拟内存大小。相比较而言堆获得的空间比较灵活,也比较大。

  4. 申请效率的比较
    栈:由系统自动分配,速度较快,但程序员是无法控制的。
    堆:由new分配的内存,一般速度比较慢,而且比较容易产生内存碎片,不过用起来最方便。

  5. 堆和栈中的存储内容
    栈:在函数调用时,第一个进栈的是主函数中的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数。在大多数c编译器中,参数是由右往左压栈的,然后是函数中的局部变量。静态变量是不入栈的。当函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,,也就是主函数的下一条指令,程序由该点继续执行。
    堆:一般是在堆的头部用一个字节存放堆得大小,其他内容自己安排。

  6. 存取效率的比较

    char str1[]="aaaaaa";
    char *str2="cccccc";
    

    第一行是在运行时刻赋值的,第二行是在编译时就已经确定的,但在以后的存取过程中,在栈上的数组比指针指向的字符串快。

STM32存储器分配

1. 随机存储器—RAM

RAM是与CPU直接交换数据的内部存储器,也叫主存(内存)。
它可以随时读写,而且速度很快,通常作为操作系统或其他正在运行中的程序的临时数据存储媒介。
当电源关闭时RAM不能保留数据(掉电数据消失哦)如果需要保存数据,就必须把它们写入一个长期的存储设备中(例如硬盘)。

2. 只读存储器—ROM

ROM所存数据,一般是装入整机前事先写好的,整机工作过程中只能读出,而不像随机存储器那样能快速地、方便地加以改写。
ROM所存数据稳定,断电后所存数据也不会改变。

  • 33
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值