一,进程在内存中的总结
上图并不代表内存分布地址次序
1,代码区,存放程序的二进制代码
2,常量区,他的生命周期和会从初始化开始到程序结束。例如,char *str = "Hello World!";字符串就存放在常量区。如下程序可以正常输出:
char* fun()
{
char *p = "Hello Word!";
return p;
}
int main()
{
char *p = fun();
puts(p);
return 0;
}
需要注意的是这里所说的常量,准确的说是“文字常量”,而非const变量。例如,const int n = 1;变量n是存放在栈上,如果是在函数中定义,会随着函数的结束就会释放掉。
3,全局数据区/静态存储区。全局变量和静态变量存放在一个地方,他们的生命周期都是贯穿整个程序。两者的区别主要在于作用域,不加修饰的全局变量,可以被整个整个工程访问,而静态变量如果定义在局部函数,则即使该变量一直没有被释放,在函数体外也是无法访问的。需要注意的是,static修饰的全局变量和函数,它们的作用域将限制在它们所在的文件。
4,堆区。堆区主要是指存放用new和malloc等动态分配方法申请的空间中的数据。堆区的数据,生命周期由程序员决定。例如,在C++中使用new申请的空间,需要程序员用delete手动来释放该段空间,不然编译器是不会自动释放。因此,如果使用不当,容易导致内存泄漏。
5,栈区。栈区数据主要包括函数内的局部变量和函数参数。它有编译器自动释放。
二,堆区和栈区的比较
栈(Stack) |
堆(Heap) |
|
申请方式 |
由OS自动分配。例如在函数声明一个局部变量int b; OS自动在栈中为b开辟空间 |
需要程序员自己申请,并指明大小,在c中malloc函数,如p1 = (char*)malloc(10); 在C++中用new运算符如p2 = new char[10]; 注意:p1和p2本身是在栈中的 |
申请后系统响应 |
只要栈的剩余空间大于所申请的空间,系统将为程序提供内存,否则将报异常提示栈移除。 |
首先应该知道操作系统有一个记录空闲内存地址的链表,当系统收到程序的申请时,会遍历该链表,寻找第一个空间大于所申请空间的堆结点,然后将该结点从空闲结点链表中删除,并将该结点的空间分配给程序,另外,对于大多数系统,会在这块内存空间中的首地址处记录本次分配的大小,这样,代码中的delete语句才能正确的释放本内存空间。另外,由于找到的堆结点的大小不一定正好等于申请的大小,系统会自动的将多余的那部分重新放入空闲链表中。 |
申请大小的限制 |
栈是向低地址扩展的数据结构,是一块连续的内存的区域。这句话的意思是栈顶的地址和栈的最大容量是系统预先规定好的,在WINDOWS下,栈的大小是2M (也有的说是1M,总之是一个编译时就确定的常数),如果申请的空间超过栈的剩余空间时,将提示overflow。因此,能从栈获得的空间较小。 |
堆是向高地址扩展的数据结构,是不连续的内存区域。这是由于系统是用链表来存储的空闲内存地址的,自然是不连续的,而链表的遍历方向是由低地址向高地址。堆的大小受限于计算机系统中有效的虚拟内存。由此可见,堆获得的空间比较灵活,也比较大。 |
申请的效率 |
栈由系统自动分配,速度较快。但程序员是无法控制的。 |
堆是由new分配的内存,一般速度比较慢,而且容易产生内存碎片,不过用起来最方便。 另外,在WINDOWS下,最好的方式是用VirtualAlloc分配内存,它不是在堆,也不是在栈是直接在进程的地址空间中保留一快内存,虽然用起来最不方便。但是速度快,也最灵活。 |
存储内容 |
在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。 |
一般是在堆的头部用一个字节存放堆的大小。堆中的具体内容有程序员安排。 |
存取效率 |
快 |
慢 |
三,程序的组成
和上述概念有一个很容易混淆的概念是程序的段组成,按照参考材料1中的说明,一个程序由BSS段、DATA段和TEXT段组成。其中BSS(Block Started by Symbol segment )段,存放程序中未初始化的全局变量的一块内存区域,一般在初始化时BSS 段部分将会清零。BSS段属于静态内存分配,即程序一开始就将其清零了。已经初始化的数据存放在DATA段。BSS段和DATA段数据最大的区别是DATA段中的数据是不作修改的放进内存中,而BSS段数据则是不占用exe文件的空间,在程序开始时初始化时(一般为0,例如一段a[1000],在exe记录为a数据占用1000*4个字节这样的信息)。因此例如,全局变量a[10000] = {0}; 和a[10000]在exe生成的空间中,前者多占用10000*4字节,后者不占用。
参考资料:
1,http://www.cnblogs.com/sigmahh/archive/2009/07/03/1516474.html