对于一个程序要运行,涉及到的内存分配是一个首要问题,这里简单说一下一个简单的程序运行所涉及到的内存分配方式。另外,在数据结构中存在堆和栈的概念,栈是一种先进后出的数据结构,堆则是一种排序方式,而在内存分配中也存在堆(heap)和栈(stack)的概念,与数据结构中的概念不同,这里简单说明在内存分配中的堆栈之间的不同。
一、内存分配方式
1、全局变量和静态变量(static变量),是由编译器自动分配和释放的,初始化的全局变量和静态变量放在同一块内存区中,未初始化的全局变量和静态变量则放在相邻的另外一块内存区中。
2、栈,是由编译器自动分配和释放的,主要是函数体的地址,参数和局部变量,静态变量不包含其中,操作方式类似于数据结构中的栈。
3、堆,是由程序员手动完成申请和释放的,像malloc和new,程序员没有手动释放的话,当程序结束时由系统释放没有释放的空间,其实现方式与数据结构中的堆完全不同,此时的堆的实现方式有些类似于数据结构中的链表。
4、程序代码区,用于存放程序的二进制代码的空间。
5、文字常量区,像常量字符串等存放在这里,程序结束后由系统释放。
一个经典的例子,由强大的网友提供:
//main.cpp
int a = 0; 全局初始化区
char *p1; 全局未初始化区
main()
{
int b; 栈
char s[] = "abc"; 栈
char *p2; 栈
char *p3 = "123456"; 123456在常量区,p3在栈上。
static int c =0; 全局(静态)初始化区
p1 = (char *)malloc(10);
p2 = (char *)malloc(20);
分配得来得10和20字节的区域就在堆区。
strcpy(p1, "123456"); 123456放在常量区,编译器可能会将它与p3所指向的"123456"优化成一个地方。
}
二、内存分配中堆和栈的区别
1.申请释放方式
在申请内存和释放内存方式方面,堆和栈有着很大的不同,先来谈谈栈是如何实现的吧。栈是编译器自动申请的,例如在主函数里面,要声明一个int变量a,那么编译器就自动开辟一块内存存放变量a。而堆则不相同,是由程序员手动申请的,只要程序员感觉程序此处需要用到多大的内存空间,那么就使用malloc或者new来申请固定大小的内存使用。栈的空间在程序结束的时候由系统或者编译器自动释放,而堆则在程序结束前由程序员手动使用delete释放,或者忘记手动释放,由系统在程序结束的时候自动回收。
2.申请后系统的相应
栈,只要栈剩余的空间大小比申请的空间小,系统就自动为其分配空间,否则就会报错说明栈空间溢出。
堆,首先要知道操作系统中有一个存放空闲存储块的链表,当程序员申请空间的时候,系统就会遍历整个链表,找到第一个比申请空间大的空闲块节点,系统会将该空闲块从空闲链表中删除,分配给程序,同时系统会记录这个空闲块的首地址和申请的大小,当程序员使用delete释放该空间的时候能够找到该存储区。另外,申请的空间不一定与找到的空闲块大小相同,多出来剩余的空闲区会被系统重新添加到空闲链表中。
3.申请的限制
栈,是一种向低地址扩展的数据结构,并且是连续的存储空间,所以栈顶和栈的最大容量是固定的,在windows下,栈的最大容量是2m或者是1m,是在编译的时候就已经确定的,当申请空间大于栈的剩余空间的时候,就会报错说明overflow,所以栈能够申请的空间是比较有限的。
堆,是一种向高地址扩展的数据结构,并且是不连续的,因为系统采用的是链表的方式存放空闲存储块,当然是不连续的,链表的遍历方向是由低向高的,所以堆能够申请的空间的大小其实等同于整个系统的虚拟内存,只要还有内存空间,那么堆就能够不受限制的申请空间,这种方式比较灵活,申请空间也较大。
4.申请效率的比较
栈,因为栈空间的申请是由系统自动完成的,所以速度快,但是不受程序员控制。
堆,空间的申请是由malloc或new来完成的,实现起来较慢,能够产生碎片,但是使用起来方便。
5.存放内容
栈,栈存放的内容,一般来说是函数地址和相关参数。当主函数要调用一个函数的时候,要对当前断点进行保存,需要使用栈来实现,首先入栈的是主函数下一条语句的地址,然后是调用函数的参数,一般情况下是按照从右向左的顺序入栈,之后是调用函数的局部变量,注意静态变量是存放在全局内存区,是不入栈的;出栈的顺序正好相反,最终栈顶指向主函数下一条语句的地址,主程序又从该地址开始执行。
堆,一般情况堆顶使用一个字节的空间来存放堆的大小,而堆中具体存放内容是由程序员来完成的。
参考资料:http://zhidao.baidu.com/question/6117772.html
补充:
全局变量、局部变量、全局静态变量、局部静态变量的区别。要从分配内存的位置和作用域入手来解释。
全局变量,分配的内存在静态存储区内存上面,其作用域是全局作用域,也就是整个程序的生命周期内都可以使用,同时,有些程序并不是由一个源文件构成的,可能有许多个源文件构成,全局变量只要在一个文件中定义,就可以在其他所有的文件中使用,当然,必须在其他文件使用extern关键字声明该变量。
局部变量,分配内存是分配在栈存储区上的,其作用域也只是在局部函数内,在定义该变量的函数内,只要出了该函数,该局部变量就不再起作用,该变量的生命周期也只是和该函数同在。
全局静态变量,分配的内存与全局变量一样,也是在静态存储内存上,其生命周期也是与整个程序同在的,从程序开始到结束一直起作用,但是与全局变量不同的是,全局静态变量作用域只在定义它的一个源文件内,其他源文件不能使用它。
局部静态变量,分配的内存也是在静态存储内存上的,其第一次初始化后就一直存在直到程序结束,该变量的特点是其作用域只在定义它的函数内可见,出了该函数就不可见了。
|