C++内存管理之一---------内存分配方式
1.内存分配方式简介
在C++中,内存分为5个区,它们分别是堆、栈、自由存储区、全局/静态存储区和常量存储区。
栈,在执行函数时,函数内局部变量的存储单元可以在栈上创建,函数执行结束时这些存储单元自动释放。栈内存分配运算内置于处理器的指令集中,效率很高,但是分配的内存容量有限。
堆,由new分配的内存块,它们的释放编译器不去管,由我们的应用程序去控制,一般一个new就对应一个delete。如果程序员没有释放掉,那么在程序结束后,操作系统会自动回收。
自由存储区,由malloc等分配的内存块,它和堆非常相似,不过它是用free来结束自己的生命的。
全局/静态存储区,全局变量和静态变量被分配到同一块内存中。在c语言中,全局变量又分为初始化和未初始化的。在c++里面没有这个区分了,它们共同占用同一块内存区。
常量存储区,这是一块比较特殊的存储区,它们里面存放的是常量,不允许修改。
2.明确区分栈和堆
void f() {
int *p = new int[5];
}
上面程序的意思是:在栈内存中存放了一个指向一块堆内存的指针p。程序会先确定堆中分配内存的大小,然后调用operator new 分配内存,然后返回这块内存的首地址。
3.堆和栈究竟有什么区别?
堆和栈的区别有一下几点:
1).管理方式不同 2).空间大小不同 3).能否产生碎片不同 4).生长方向不同 5).分配方式不同 6).分配效率不同
管理方式:对于栈,是由编译器自动管理,无需我们手工控制;对于堆,释放工作由程序员控制,容易产生memory leak.
空间大小不同:一般在32位系统下,堆内存可以达到4G的空间,从这个角度看堆内存是没有什么限制的。但是对于栈,一般都是有一定的空间大小的。
碎片问题:对于堆来讲,频繁的new/delete势必会造成内存空间的不连续,从而造成大量的碎片,使程序效率降低。对于栈来说,则不会有这个问题。因为栈是先进后出的队列,它们是如此的一一对应,以至于永远都不可能有一个内存块从栈中弹出,在它弹出之前,在他上面的后进的栈内容已经被弹出。
生长方向:堆,生长方向是向上的,也就是向着内存地址增加的方向;栈,生长方向是向下的,是向着内存地址减小的方向增长。
分配方式:堆都是动态分配的。栈有两种分配方式:静态分配和动态分配。静态分配是编译器完成的,比如局部变量的分配。动态分配由malloc函数进行分配,但是栈的动态分配和堆是不同的,他的分配是由编译器进行释放,无需我们手工实现。
分配效率:栈是机器系统提供的数据结构,计算机会在底层对栈提供支持:分配专门的寄存器存放栈的地址,压栈出栈都由专门的指令执行,这就决定了栈的效率比较高。堆则是c/c++函数库提供的,他的机制很复杂。
总结:堆和栈相比,由于大量new/delete的使用,容易造成大量的内存碎片;由于没有专门的系统支持,效率很低;由于可能引发用户态和核心态的切换,内存的申请,代价变得更加昂贵。所以在程序中栈是应用最广泛的。就算是函数调用也利用栈去 完成,函数调用过程中的参数,返回地址,局部变量都采用栈的方式存放。