乐趣区

关于c:C语言内存分区堆栈全局静态存储区自由存储区代码区与可执行程序的三段Text段Date段Bss段

一、c 语言五大内存分区

栈区(stack): 寄存函数形参和局部变量(auto 类型),由编译器主动调配和开释

堆区(heap): 该区由程序员申请后应用,须要手动开释否则会造成内存透露。如果程序员没有手动开释,那么程序完结时可能由 OS 回收。

全局 / 动态存储区:寄存全局变量和动态变量(包含动态全局变量与动态局部变量),初始化的全局变量和动态局部变量放在一块,未初始化的放在另一块

文字常量区:常量在对立运行被创立,常量区的内存是只读的,程序完结后由零碎开释。

程序代码区:存放程序的二进制代码,内存由系统管理

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

auto 变量:函数的局部变量,如果没有申明为 static, 函数中定义的局部变量全副为 auto 类型,auto 变量包含未加 static 申明的局部变量和函数的形参。在函数调用时零碎会给他们调配存储空间,在函数调用完结后会主动开释这些空间。属于动静存储形式。

static 变量:用 static 申明的局部变量在调用完结后不会隐没而保留原来的值。static 局部变量定义应用后值会存储下来。所以应用 static 局部变量定义只须要一次赋值。动态局部变量的作用域仅限于所定义的函数。但函数完结后变量的值会保留。直到整个程序运行完结。全局变量从定义开始作用于整个文件直至程序运行完结。

register 寄存器变量:寄存器变量能够进步 c 语言的执行效率,行将局部变量的值存入 CPU 的寄存器中。须要留神的是!!!:1. 只有动静存储的变量(主动局部变量和形参)才能够作为寄存器变量来存储,部分动态变量不能够定义为寄存器变量。2. 计算机的寄存器数目是无限的,所以不能定义任意多个寄存器变量。

extern 内部变量:即全局变量的内部表现形式,是在函数内部定义的变量。全局变量的作用域为从定义开始到源文件完结。exten 对该变量作内部变量申明,扩大变量作用域。

三、可执行程序内存空间与逻辑地址空间的映射与划分
 
右边是 UNIX 零碎的执行文件,左边是过程对应的逻辑地址空间的划分状况
首先是栈区(堆栈区 stack), 堆栈是由编译器主动调配开释,寄存函数的参数和局部变量的值(auto 类型),操作形式相似于数据结构中的栈。栈的申请是由零碎主动调配,如在函数外部申请一个局部变量 int h, 同时判断所申请空间是否小于栈的残余空间,如果小于则为其开拓空间,为程序提供内存,否则将报异样提醒栈溢出。
堆(heap),堆个别由程序员调配开释,若程序员不开释,程序完结可能由 OS 回收。它与数据结构中的堆是两回事,调配形式相似于链表,申请则是程序员本人操作应用 malloc 或 new。申请过程比较复杂,当零碎收到程序的申请时,会遍历记录闲暇内存地址的链表,以求寻找第一个空间大于所申请空间的堆节点,而后将该节点从闲暇节点链表中删除,并将该节点的空间调配给程序,有些状况下,新申请的内存块的首地址记录本次调配的内存块的大小,这样在 delete 尤其是 delete[]时能正确的开释内存空间。
下边是全局动态存储区,全局变量与动态变量的存储是放在一块的,初始化的全局变量与动态变量寄存在一块区域,未初始化的全局变量与未初始化的动态变量寄存在相邻的另一块区域。
文字常量区,常量字符串就是放在该局部,只读存储区,程序完结后由零碎开释
程序代码区,存放程序的二进制代码区。
四、存储类型关键字定义变量与函数作用域与生命周期

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. 存取效率的比拟

1 char str1[]=”aaaaaa”;

2 char *str2=”cccccc”;

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

 

退出移动版