1、划分内存四区的意义
C语言程序中,根据是 局部变量,全局变量,常量 还是通过 malloc
等类似的函数分配内存空间,把他们放到对应的 内存区中。这样就赋予了这些变量或常量不同的生命周期,不同的释放方式。
根据我们程序的需要,我们在编码过程中,声明不同的变量类型,使他们有不同的声明长度,不同的释放方式,给我们更大的灵活编程。
2、内存四区分类
序号 | 区域 | 描述 |
---|---|---|
1 | 栈区(stack) | 保存函数现场(形参、返回地址、相关运行状态)、函数内局部变量 栈顶 从高地址 向低地址 的方向生长由程序管理,发生 出栈 时释放 |
2 | 堆区(heap) | malloc /free ,new /delete 堆 从低地址 向高地址 的方向生长由程序员 手动释放 |
3 | 读写数据区 | .data 数据段:初始化的全局变量 /静态变量 ,.bss段:未初始化的 全局变量 /静态变量 由OS管理,程序结束时 才释放 |
4 | 代码区 | .text 文本段:各个函数体的二进制代码 .rodata 只读数据段 :用于存储只读数据,如 字符串常量。 由OS管理,程序结束时 才释放 |
3、内存堆栈图
4、栈和堆的比较
4.1 申请方式
栈
:由系统自动分配。
堆
:需要程序员自己申请,并指明大小。在C中用 malloc 函数,在C++中用 new 运算符。
4.2 存储内容、数据
栈:在函数调用时,第一个 进栈 的是主函数中的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数。
- 在大多数的C编译器中,参数是 由 右往左 入栈 的,然后是函数中的局部变量。
(注意:静态变量是 不入栈的) - 当本次函数调用结束后,局部变量先 出栈,然后是参数,最后 栈顶指针 指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。
堆:一般是在 堆 的头部用一个字节,存放 堆 的大小。
堆 中的具体内容由程序员安排。
4.3 申请后系统的响应
栈
:只要 栈
的剩余空间大于所申请空间,系统将为程序提供内存,否则将报异常提示 栈
溢出。
堆
:操作系统有一个记录空闲内存
地址的 链表
,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的 堆节点
,然后将该节点从 空闲节点链表 中删除,并将该节点的空间分配给程序。
对于大多数系统,会在这块 内存空间
中的 首地址
处记录本次分配的大小。这样,代码中的 delete
语句才能正确地释放本内存空间。
另外,由于找到的 堆节点
的大小不一定正好等于申请的大小,系统会自动地将多余的那部分重新放入 空闲链表
中。
4.4 申请大小的限制
栈:栈 是向 低地址
扩展的 数据结构,是一块连续的内存的区域。
栈顶
的地址和 栈
的最大容量是系统预先规定好的,在Windows下,栈
的大小是2MB(也有的说是1MB,总之是一个编译时就确定的常数)。
如果申请的空间超过 栈
的剩余空间,将提示overflow。因此,能从 栈
获得的空间较小。
堆:堆 是向 高地址
扩展的 数据结构,是不连续的内存区域。
这是由于系统是用链表存储空闲内存地址的,自然是不连续的。而 链表 的遍历方向是由 低地址
向 高地址
。
堆 的大小,受限于计算机系统中,有效的虚拟内存。
由此可见,堆 获得的空间比较灵活,也比较大。
4.5 申请效率
栈:由 系统自动分配,速度较快。但程序员无法控制。
堆:是由new分配的内存,一般速度比较慢。
而且容易产生内存碎片
,不过用起来最方便。
4.6 存取效率
栈 的数据存取 比 堆
的快。