一个完整程序,在内存中的分布情况:
1、代码区(code area) 存放函数体(类成员函数、全局函数)的二进制代码。
2、全局区(data area) 静态存储区,存放全局变量、静态变量,初始化变量的在一块区域(低地址区域),未初始化变量在另一块区域(高地址区域BSS)。文字常量、字符串常量,程序结束后由系统释放。
3、堆区(heap area) 由低地址向高地址增长。一般new、malloc分配,由程序员分配和释放,分配方式类似于链表。
4、栈区(stack area) 由高地址向低地址增长。存放函数形参、局部变量、返回值等,由编译器自动分配、释放。
栈区再向下是操作系统和内核调用的一些内存地址。
例:
int a = 0;//全局初始化区
char *p;//全局未初始化区
int main(void)
{
int b;//栈区
static int c = 0;//全局初始化区
char s[] = "abc";//栈区
char *p2;//栈区
char *p3 = "123";//栈区,123在常量区
p1 = new char[10];
p2 = new char[20];//分配的空间在堆区
strcpy(p1,"123");//123在常量区
return 0;
}
堆和栈的比较
1、申请方式 stack:由系统自动分配。比如在函数中一个局部变量 char a;系统自动在栈中为a开辟空间。heap:由程序员申请,并指定大小。p1 = new char[10]; p2 = (char *)malloc(10);
2、申请后系统的响应 stack:只要栈的剩余空间大于申请空间,系统将为程序提供内存,否则提示栈溢出。heap:操作系统有一个记录空闲内存地址的链表,当系统收到程序申请时,会遍历链表,寻找第一个空间大于申请空间的堆结点,然后将结点从空闲地址链表中删除,将结点的空间分配给程序,多余的空间会重新放入空闲链表中。
3、申请的大小限制 stack:windows中,栈向低地址扩展,连续的内存区域,大小一般是2M(编译器)。heap:堆向高地址扩展,不连续的内存区域,由空闲内存链表管理,大小受限于系统中有效的虚拟内存。
4、申请效率stack:栈由系统自动分配,速度快。heap:堆由new/malloc函数分配,速度较慢,容易产生内存碎片,方便。
5、存取效率 xx 栈上的数组比指针所指向的字符串快。
6、存取内容 stack:函数调用时,第一个进栈的是函数调用语句的下一条指令的地址,然后是函数的参数从右往左入栈(编译器),再是局部变量入栈。函数调用结束后,局部变量出栈,参数出栈,栈顶指针指向函数调用的下一条指令,程序继续运行。heap:堆的头部用一个字节存放堆的大小,具体内容由程序员决定。
堆和栈的区别:
1、管理方式不同;堆由程序员控制,容易产生memory leak,栈由编译器自动管理。
2、空间大小不同;堆空间可以达到4G,栈有一定的空间大小,一般是2M。
3、生长方向不同;堆的生长方向->向着内存地址增加的方向增长,栈的生长方向->向着内存地址减小的方向增长。
4、分配方式不同;堆是动态分配的。栈有静态分配和动态分配。
5、分配效率不同;堆是C/C++函数库提供的,机制复杂,根据一定的算法实现。栈是机器系统提供的,在低层有专门的寄存器和栈指令,效率高。堆的效率比栈低得多。
6、能否产生碎片不同;对于堆,频繁的使用new/delete会造成内存空间不连续,产生大量碎片。对于栈,不会存在这个问题,先进后出。
堆和栈相比,由于大量的new/delete的使用,容易造成大量的内存碎片,效率低等因素,推荐使用栈。但是堆更加的灵活,在分配大量的空间时,堆才是更好的选择。无论是堆还是栈,都要防止越界现象的发生(程序崩溃、破坏堆栈结构)。
new/delete 和 malloc/free
new分配空间会调用类的构造函数,而malloc函数仅仅是一个函数调用。delete在释放堆空间的时候会调用析构函数,而free函数不会。