C++中内存的分配方式和分配区域.
堆、栈、静态存储区.
堆(heap):由程序员分配,new和delete。它们的释放编译器不管,由应用程序控制,一般一个new就要对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。堆可以动态地扩展和收缩。
栈(stack):就是那些由编译器在需要的时候分配,在不需要的时候自动清除的变量的存储区域。里面的变量通常是局部变量、函数参数等。在一个进程中,位于用户虚拟地址空间顶部的是栈,编译器用它来实现函数调用。
全局/静态存储区:内存在程序编译时就已分配好,这块内存在程序的整个运行期间都存在。程序结束后由系统释放。例如:全局变量,static变量。
程序例子://当然并不是我写的.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#include <iostream> using namespace std; int a = 0;//全局初始化区 char *p1;//全局未初始化区 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"优化成一个地方。 } |
堆栈知识:
首先看下面一段代码:
1 2 3 4 |
void f() { int *p = new int[5]; } |
我们可以看到,有一个指针p,对它分配了5个int型空间.
看到new我们可以知道,分配的是堆上的空间.
p是函数f()的局部变量,所以在栈上.
故这句话可以理解为:在栈内存中存放了一个指向(5个int型空间的堆内存)的指针 p.
当我们要释放这块内存的时候:就使用 delelte []p;(注意删除的是数组不是数.)
那么,堆和栈有什么不同呢:
- 管理方式不同
- 空间大小不同
- 产生碎片不同
- 生长方向不同
- 分配方式不同
- 分配效率不同
1.管理方式不同:
对于栈来讲,是编译器自动管理,无需手动控制.
对于堆来说,释放工作由程序员控制。
2.空间大小不同:
栈的大小:在WINDOWS下,栈的大小是2M(也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。
堆的大小:堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。
3.产生碎片不同:
对于堆来讲,频繁的 new/delete 势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来讲,则不会存在这个问题,因为栈是先进后出的队列,他们是如此的一一对应,以至于永远都不可能有一个内存块从栈中间弹出,在他弹出之前,在他上面的后进的栈内容已经被弹出了。
4.生长方向不同:
对于堆来讲,生长方向是向上的,也就是向着内存地址增加的方向;
对于栈来讲,它的生长方向是向下的,是向着内存地址减小的方向增长。
5.分配方式不同:
堆都是动态分配的,没有静态分配的堆。
栈有2种分配方式:静态分配和动态分配。
静态分配是编译器完成的,比如局部变量的分配。
动态分配由 alloca 函数进行分配。
但是栈的动态分配和堆是不同的,他的动态分配是由编译器进行释放,无需我们手工实现。
6.分配效率不同:
栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都有专门的指令执行,这就决定了栈的效率比较高。
堆则是 C/C++ 函数库提供的,它的机制是很复杂的,例如为了分配一块内存,库函数会按照一定的算法(具体的算法可以参考数据结构/操作系统)在堆内存中搜索可用的足够大小的空间,如果没有足够大小的空间(可能是由于内存碎片太多),就有可能调用系统功能去增加程序数据段的内存空间,这样就有机会分到足够大小的内存,然后进行返回。显然,堆的效率比栈要低得多。
一般所说的堆栈(stack)往往是指栈,先进后出,它是一块内存区。用以存放程序的局部变量,临时变量,函数的参数,返回地址等。在这块区域中的变量的分配和释放由系统自动进行。不需要用户的参与。
而在堆(heap,先进先出)上的空间则是由用户进行分配,并由用户负责释放