C_CPP进程内存空间分布

内存分区

内存分布分为5个部分,从高地址到低地址依次为栈区(stack),堆区(heap),未初始化数据段(uninitialized data),初始化数据段(initialize data)和代码段(text)。

有些文档也把初始化的数据段和未初始化的数据段合称全局区。

1. 文本段--只读、共享,操作系统管理

文本段也叫代码段,是对象文件或内存中程序的一部分,其中包含可执行指令。文本段在堆栈的下面,是防止堆栈溢出覆盖它。

通常代码段是共享的,对于经常执行的程序,只有一个副本需要存储在内存中;代码段是只读的,以防止程序以外修改指令。

2. 初始化的数据段

通常称为数据段,是程序的虚拟地址空间的一部分,它包含程序员初始化的全局变量和静态变量以及常量,可以进一步划分为只读区域和读写区域。

例如,C中的char=“hello world”的全局字符串,以及main(例如全局)之外的int debug=1这样的C语句,将被存储在初始的读写区域中。

而像const char字符串=“hello world”这样的全局C语句常量字符串文字“hello world”被存储在初始化的只读区域中,并在初始化的读写区域中存储字符指针变量字符串。

3. 未初始化的数据段--内核初始化为0

通常称为bss段,这个段的数据在程序开始之前有内核初始化为0,包含所有初始化为0和没有显示初始化的全局变量和静态变量。

这个段在程序开始之前由内核初始化为全0,所以不在可执行文件中占用位置,可减少可执行文件体积。

BSS段在磁盘上不是真的占用变量大小的空间,elf中它仅是在该段中记录了所有未初始化全局变量与局部静态变量的大小总和,至于每个变量的大小则存储在符号表的size属性中。即:

BSS段内容:无内容,它将在段表中占一个段描述符,该段描述符的size属性将记录未初始化的全局变量与局部静态变量的大小总和。每个未初始化全局对象与静态对象的大小,存储在符号表的 size 属性中。

bin文件中不存在bss段,只有text和data段。在bin文件中,指向bss变量时只是bss变量的地址,该地址为程序运行时的内存地址(bin文件中保存偏移量)。

elf反汇编:
80002330:    9af1ac23              sw    a5,-1608(gp) # 800fc2c8 <chipid>  ;chipid为全局未初始化数据,存储在bss段。800fc2c8为变量内存地址,超过了bin文件大小,保存了偏移量。
bin反汇编:
2330:    9af1ac23              sw    a5,-1608(gp)

4. 堆--程序员管理

堆是动态内存分配通常发生的部分。内存分配由低到高,分配方式类似于数据结构的链表。堆区域从BSS段的末尾开始,并从那里逐渐增加到更大的地址。

堆是由程序员自己分配的,或程序结束后由操作系统自动回收。堆区域由所有共享库和进程中动态加载的模块共享。(malloc和new从堆区分配内存)

5. 栈--编译器分配管理

存放自动变量,以及函数调用时保存的信息。每当进行函数调用时,函数的实参和返回地址以及调用者的上下文环境会被存放在栈中;栈区由编译器自动分配,从高地址向低地址扩展。

在函数调用时,第一个进栈的是主函数中后的下一条指令(函数调用语句的下一条可执行语句)的地址,然后是函数的各个参数,在大多数的C编译器中,参数是由右往左入栈的,然后是函数中的局部变量。注意静态变量是不入栈的。 当本次函数调用结束后,局部变量先出栈,然后是参数,最后栈顶指针指向最开始存的地址,也就是主函数中的下一条指令,程序由该点继续运行。

内存分区的意义

不同区域存放的数据,赋予不同的生命周期,给编程更大的灵活性。

 

参考:

1. bss段

posted @ 2015-10-14 22:27  yuxi_o  阅读(720)  评论(0编辑  收藏  举报