一个C++程序编译后占用的内存分为如下几个部分:
-
栈:由编译器自动分配释放,存放函数的参数值,局部变量的值。在一个进程中,位于用户虚拟地址空间顶部的是用户栈,编译器用它来实现函数的调用。
-
堆:由程序员分配和释放,若程序员不释放,则程序结束时被OS回收。存放由new,malloc分配的内存,可动态扩展和收缩。
-
全局区(静态区):全局变量和静态变量的存储是放在一起的:初始化的全局变量和初始化的静态变量在一块区域;未初始化的全局变量和未初始化的静态变量在相邻的另一块区域。
-
文字常量区:常量字符串放在这里,程序结束后由系统释放。
-
程序代码区:存放函数体的二进制代码。
- 管理方式不同:栈由编译器自动管理,无需手动控制;堆由程序员控制,容易产生memory leak。
- 能否产生碎片:对于堆来说,频繁地new/delete势必造成内存空间的不连续,从而造成大量碎片,使程序效率降低;对于栈来说,不会存在这个问题,因为栈是后进先出的队列,一一对应,不会出现某个内存块从栈中间弹出。
- 生长方向:对于堆来说,生长方向向上,向着内存地址增加的地方;对于栈,生长方向向下,向着内存地址减小的方向。
- 分配效率:栈是计算机系统提供的数据结构,操作系统在底层对栈提供支持,分配专门的寄存器存放栈的地址,压栈出栈有专门的指令执行,这就决定了栈的效率比较高。堆则是由C/C++函数库提供,显然栈的效率比堆高。
//main.cpp int a = 0; //全局初始化区 char *p1; //全局未初始化区 int main() { int b; //栈区 char s[] = "abc"; //栈区 char *p2; //栈区 char *p3 = "123456"; //123456在常量区,指针p3在栈上。 static int c =0; //全局(静态)初始化区 p1 = (char *)malloc(10); //分配得来得10和20字节的区域就在堆区。 p2 = (char *)malloc(20); strcpy(p1, "123456"); //123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。 }
new和malloc的区别
- new/delete 是C++关键字(操作符),需要编译器支持。malloc/free 是库函数,需要头文件支持;
- 使用new 操作符申请内存分配时无须指定内存块的大小,编译器会根据类型信息自行计算。而malloc 则需要显式地指出所需内存的尺寸。
- new 操作符内存分配成功时,返回的是对象类型的指针,类型严格与对象匹配,无须进行类型转换,故new 是符合类型安全性的操作符。而malloc 内存分配成功则是返回void ,需要通过强制类型转换将void指针转换成需要的类型。
- new 内存分配失败时,会抛出bad_alloc 异常。malloc 分配内存失败时返回NULL。
- new 会先调用operator new 函数,申请足够的内存(通常底层使用malloc 实现)。然后调用类型的构造函数,初始化成员变量,最后返回自定义类型指针。delete 先调用析构函数,然后调用operator delete 函数释放内存(通常底层使用free实现)。malloc/free 是库函数,只能动态的申请和释放内存,无法强制要求其做自定义类型对象构造和析构工作。