您的位置:首页 > 编程语言 > C语言/C++

C/C++学习笔记15:堆区与栈区的区别

2014-08-15 14:30 218 查看
其实在说明堆栈区别的时候,不能不提到堆栈的来源,堆栈的来源往往又是内存管理中重要的一部分。

所以本节内容主要先讲述一下内存管理的基本概念、内存的分配方式、C语言编译后的可执行结构与存储结构、堆栈的区别。

1.基本的分区

其实C程序在未进入内存之前在存储时分为:代码区、数据区、未初始化数据区三个部分。

代码区:代码区主要是存放CPU执行的机器指令的。通常代码区是可以共享的,因为对于频繁被执行的程序,只需要在内存中有一份代码即可。为了防止代码意外的修改了它的指令,因此要求代码区的内容是只读的。

数据区:该区包含了在程序中明确被初始化的全局变量、静态变量(包括全局静态变量和局部静态变量)和常量数据(如字符串常量)。

未初始化数据区:存入的是全局未初始化变量。数据在程序开始执行之前被内核初始化为0或者空指针(NULL)。

上述都是可执行代码在存储时的结构,而当可执行代码运行时的结构呢,就如下图所示:



问题一:为什么要分这么多区呢?

因为一个进程在代码执行过程中,代码根据流程依次执行,只需要访问一次,当然跳转和递归可能会执行多次,而数据一般需要访问多次,因此单独开辟空间以方便访问和节约空间。

临时数据以及需要再次使用的代码放到栈区,生命周期短。

全局数据和静态数据有可能在整个程序执行过程中都要访问,因此单独存储管理。

问题二:各个类型的数据是如何存放的,分别存放在哪个区。

这个问题完全可以重新放在一个章节中来讲,一个程序中主要涉及到了哪些变量,这些变量又分别存放在内存中的哪一个部分?

把上述的内容简单的总结一下,内存可以分为4个区

代码区:顾名思义存放运行的代码的。

全局数据区(静态区):存放全局数据和静态数据以及一些常量

栈区:存放局部变量、函数调用时返回的地址、参数压栈、返回数据等

堆区:存放程序动态分配的内存。

其实还是不够详细,那我们再来详细的划分,这里面主要是全局数据区的部分,上面提到了区域划分的问题提到了数据区和未初始化的数据区。其实这都在全局数据区中,只是这里面有分为了相邻的两个区域。结果就成了:全局变量和静态变量的存储放在一块。初始化的全局变量和静态变量放在一块了,而未初始化的全局变量和静态变量放在另一个相邻的区域内。还有一个是专门放常量的地方。

好好区别静态局部变量,静态全局变量,局部变量,全局变量。

只要是静态变量都放在静态区,全局变量也放在静态区,但是局部变量是放在栈区。

2:内存分配方式

在C语言中主要有静态分配内存和动态分配内存的两种方式。

静态分配:编译器在处理程序源代码时分配

动态分配:程序在执行时调用malloc库函数申请分配。(这主要是在堆区)

二者的区别:

(1)静态对象有名字,可以直接对其进行操作,而动态对象没有名字的变量,只能通过指针间接的对其操作

(2)静态对象的分配与释放由编译器自动处理,而动态对象必须由程序猿显示的管理,它通过malloc()和free两个函数(C++中为new和delete运算符来操作,C++中的new和delete可参考:/article/9222362.html

3:堆区与栈区的区别

(1)管理方式不同

栈由编译器自动管理,无需程序员手工控制;而堆空间的申请释放工作由程序猿控制,容易产生泄露

(2)空间大小不同

栈是向低地址扩展的数据结构,是一块连续的内存区域。即:栈顶的地址和栈的最大容量由系统预设,当申请的空间超过栈的剩余空间,将溢出,用户能够从栈获得的空间较小

堆是由高地址扩展的,是不连续的内存区域。因为系统是用链表来存储空闲的地址的,且链表的遍历方向是由低地址向高地址的,由此可见,堆获得的空间灵活也较大。

(3)是否产生碎片

因为栈是一个连续的内存区域,所以不会产生碎片,而堆是不连续的,频繁的malloc和free就会造成内存不连续,从而造成大量的碎片,使程序效率降低。

(4)增长方向不同

堆的增长方向是向上的,即向着内存地址增加的方向;栈是向着低地址的方向扩展的,向着内存地址减小的方向。

(5)分配方式不同

一个是静态分配,一个是动态分配

(6)分配效率不同

栈是机器系统提供的数据结构,计算机会在底层对栈提供支持,分配专门的寄存器来存放栈的地址,压栈和出栈都有专门的指令执行,堆是由C函数库提供的,它的机制很复杂。堆的效率要比栈的效率低很多。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: