先认识内存中的几个区,下面的区都在内存中,意味着掉电会丢失。但是这不意味着内存条里面真的是这样,包括操作系统的分页都只是对内存的一种管理方式,或者说是虚拟的逻辑管理。
栈区(stack):由编译器自动分配释放,存放函数的参数值、局部变量、返回值等。其操作方式类似于数据结构中的栈。
堆区(heap):自己分配自己释放,内存分配方式类似于数据结构的链表。
全局区(静态区)(static):用于全局变量和静态变量的存储。分为:已初始化读写数据段(RW data),未初始化数据段(BSS,Block Started By Symbol)。
文字常量区,即只读数据段(RO data):常量字符串和使用const定义的变量所用。
程序代码区(Code或Text):存放函数体的二进制代码。
堆区和栈区属于动态区域,其他的属于静态区域,为什么这么说?来看看他们生成的过程:
初始化的时候:开辟未初始化数据段。
编译生成二进制代码,开辟代码段。
链接:开辟只读数据段和已初始化读写数据段。
运行:根据代码开辟堆区和栈区。
在运行时候才开辟,不运行则不会开辟,称为动态区域是不是很合理。
来看例子加深理解:
int a=0; //全局初始化区
char *p1; //全局未初始化区
const int A = 10; //只读区
main()
{
Int b;栈
char s[]=”abc”; //栈
char *p2; //栈
static int c = 0; //全局(静态)初始化区
char *p3=”123456″; //123456\0在常量区,p3在栈上。
p1 = (char*)malloc(10);
p2 = (char*)malloc(20); //分配得来得10和20字节的区域就在堆区。
strcpy(p1,”123456″); //123456\0放在常量区,编译器可能会将它与p3所向”123456″优化成一个地方。
}
堆和栈的区别
堆区和栈区用的最多,堆区用malloc或new申请,用delete和free释放;栈区自动分配和释放。这是第一点区别:申请方式。还有很多其他的区别,先看看系统是怎么开辟堆和栈的吧:
栈:当线程创立的时候,系统会为其开辟一个栈区,是一块连续的向低地址扩展存储区,能分配多大取决于操作系统和硬件配置还有当时的环境。但是因为需要连续,所以不会很大。所以如果太多的递归调用(需要栈记录返回值和返回位置)和内存分配(定义10亿个变量),则会导致栈溢出,所以如果不确定变量大小不要用栈。
堆:操作系统有一个记录空闲地址的链表,当我们申请堆区的时候,操作系统会遍历链表,寻找第一个空间够的(当然可能现在的系统更优化,比如找一个大小更接近的),然后将该节点从链表删除,空间分给程序,多余的部分再放回链表。(会导致碎片化)所以堆区是不连续的,向高地址扩展的存储区。很大,但是要记得释放,不然会内存泄露。如果是多线程的程序,会共享堆区,但是栈区独立,所以并行存储是堆控制的。
总结起来:
申请方式
大小不同
栈适合“杀鸡”,堆适合“宰牛”。
一个会栈溢出,一个会内存泄露。
一个向低地址连续,一个向高地址不连续。