C程序的存储空间布局

Posted Merlin的公开日志

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C程序的存储空间布局相关的知识,希望对你有一定的参考价值。

历史沿袭至今,C程序一直由下列几部分组成:

 

1. 正文段(.text)。这是由CPU执行的机器指令部分。通常,正文段是可共享的,所以即使是频繁执行的程序(如文本编辑器、C编译器和shell等)在存储器中也只需有一个副本,另外,正文段常常是只读的,心防止程序由于意外而修改其指令。

2. 初始化数据段(.data)。通常将此段称为数据段,它包含了程序中需明确地赋初值的变量(已经初始化的非零全局变量)。例如,C程序中任何函数之外的声明:

int maxcount = 99;

使此变量以其初值存放在初始化数据段中。

3. 未初始化数据段(.bss)。通常将此段称为bss段,这一名称来源于时期汇编程序的一个操作符,意思是“由符号开始的块“(block started by symbol),在程序开始执行之前,(通常)内核将此段中的数据初始化为0或空指针。存放程序中未初始化的和零值全局变量。函数外的声明:

long sum[1000];

使此变量存放在非初始化数据段中。

text和data段都在可执行文件中,由系统从可执行文件中加载;而bss段不在可执行文件中,由系统初始化。

4. 栈(stack)。按内存地址由高到低方向生长,其最大大小由编译时确定。自动变量以及每次函数调用时所需保存的信息都存放在此段中。每次函数调用时,其返回地址以及调用者的环境信息(如某些机器寄存器的值)都存放在栈中。然后,最近被调用的函数在栈上为其自动和临时变量分配存储空间。通过心这种方式使用栈,C递归函数可以工作。递归函数每次调用自身时,就用一个新的栈帧,因此一次函数调用实例中的变量集不会影响另一次函数调用实例中的变量。

5. 堆(heap)。自由申请的空间,按内存地址由低到高方向生长,其大小由系统内存/虚拟内存上限决定。通常在堆中进行动态存储分配。由于历史上形成的惯例,堆位于未初始化数据段和栈之间。

 每个线程都会有自己的栈,但是堆空间是共用的。

上面图示中显示了这些段的一种典型安排方式。这是程序的逻辑布局,虽然并不要求一个具体实现一定以这种方式安排其存储空间,但这是一种我们便于说明的典型安排。对于32位Intel x86处理器上的Linux,正文段从0x0804 8000单元开始,栈底则在0xC000 0000之下开始(在这种特定结构中,栈从高地址向低地址方向增长)。堆顶和栈顶之间未用的虚地址空间很大。

  a.out中还有基于其他类型的段,如包含符号表的段、包含调试信息的段以及包含动态共享库链接表的段等。这些部分并不装载到进程执行的程序映像中。

从上图中还可以注意到,未初始化数据段的内容并不存放在磁盘程序文件中。其原因是,内核在程序开始运行前将它们都设置为0。需要存放在磁盘程序文件中的段只有正文段和初始化数据段。

  size(1)命令报告正文段、数据段和bss段的长度(以字节为单位)。例如:

$size /usr/bin/cc  /bin/sh

 

 

 

 

这个例子是在Ubuntu x86_64上进行的,其中第4列和第5列是分别民以十进制和十六进制表示的3段总长度。

 

参考资料:

UNIX环境高级编程(第3版) [Advanced Programming in the UNIX Environment, Third Edition] ; [美] W. Richard Stevens,[美] Stephen A. Rago 著;戚正伟张亚英尤晋元 译; 人民邮电出版社 第7.6节

以上是关于C程序的存储空间布局的主要内容,如果未能解决你的问题,请参考以下文章

Linux下C程序的存储空间布局

Linux下C程序的存储空间布局

Linux下C程序的存储空间布局

存储类生命周期作用域链接域

面试 -- Java内存布局图以及java各种存储区详解

C语言编程程序的内存如何布局