1 内存空间逻辑组织
A 静态数据区:内存在程序启动的时候才被分配,而且可能直到程序开始执行的时候才被初始化,如函数中的静态变量就是在程序第一次执行到定义该变量的代码时才被初始化。所分配的内存在程序的整个运行期间都存在,如全局变量,static变量等。
注意:初始化的全局变量和静态变量在一块区域,未初始化的全局变量与静态变量在相邻的另一块区域,同时未被初始化的对象存储区可以通过void*来访问和操纵,程序结束后由系统自行释放。
B 代码区:存放函数体的二进制代码;
C 栈区:存放自动变量。在执行函数时,函数内局部变量的存储单元都可以在栈上创建,函数执行结束时这些存储单元由编译器自动释放,超出其作用域外的操作没有定义。栈内存分配运算内置于处理器的指令集中,效率很高,但分配的内存容量有限。栈存放函数的参数值,局部变量的值等。
D 堆区(自由存储区):在运行的时候调用程序(如C中的malloc或C++中的new)分配内存,可以在任何时候决定分配内存及分配的大小,用户自己负责在何时释放内存(如用free或delete)。堆中的所有东西都是匿名的,这样不能按名字访问,而只能通过指针访问。
堆需要一种策略来保存其内存是否已分配的信息。一种策略是建立一个可用块(自由存储区)的链表,每块由malloc分配的内存块都在自己的前面标明自己的大小,一般而言都经过边界对齐(alignment)处理,堆的大小受限于计算机系统中有效的虚拟内存。
堆的末端由一个称为break 的指针来标识,当堆管理器需要更多内存时,它可以通过系统调用brk和sbrk来移动break指针,一般情况下不必显式地调用brk,如果分配的内存容量很大,brk会被自动调用。用于管理内存的调用有:
Malloc和free--从堆中获得内存以及把内存返回给堆;
brk与sbrk――调整数据段的大小至一个绝对值(通过某个增量)。
注意:程序可能无法同时调用malloc()与brk(),因为如果使用了malloc,malloc希望当你调用brk与sbrk时,它具有唯一的控制权。由于sbrk向进程提供了唯一的方法将数据段内存返回给系统内核,所以如果使用了malloc,就有效地防止了程序的数据段缩小的可能性。
此处的堆与数据结构中的堆是两回事,它的分配方式类似于链表。
由于堆中的空间由用户负责分配及释放,因此需要注意内存泄漏的问题。
另外实际上堆区与自由存储区并不是一回事,详细信息见exceptional c++条款35。
E 文字常量区(常量数据区):存放常量字符串等在编译期间就能确定的值,在程序结束后由系统自动释放。类对象不能存在于这个区域中。在本区域中所有的数据都是只读的,任何企图修改本区域数据的行为都会造成无法预料的后果。
演示内存分布的示例如下:(示例需要更改完善,同时解决其中的bug)
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"优化成一个地方。
}