C程序一般由正文段初始化数据段未初始化数据段组成。

1 正文段

正文段(text segment)存储的是CPU执行的机器指令。一般正文段是共享的,这样的话对于那些频繁执行的程序(比如编辑器、shell等)只需要在内存中保存一份副本就可以了。另外,正文段一般都是只读的,防止程序由于意外修改了自身的指令。

2 初始化数据段

一般又称为数据段(data segment),这里存储的是程序中定义于函数体外且明确初始化的变量。我们常说的全局变量如果明确初始化了的话就存储在这里。比如:int maxcount = 99;.

3 未初始化数据段

一般又称为bss段(bss segment),bss是一个早期的汇编运算符“block started by symbol”。我们定义于函数体外的变量如果没有明确初始化的话就存储在这里。比如:int maxcount;.

程序开始执行前,对于bss段的数据,内核会将其初始化为0或者空指针(NULL)。这就是为什么全局变量可以不显式的初始化的原因。

4 栈

栈(Stack)我们应该都很熟悉,局部变量(又称自动变量)以及每次函数调用的相关信息都存储在这里。每次函数调用,函数内的局部变量、函数的返回地址、调用者的环境信息都存储在栈里面。而且,每次调用都是分配一个新的栈帧,所以递归调用时变量并不会冲突。

5 堆

堆(Heap)我们也比较熟悉。动态分配的内存都来自堆。堆一般位于未初始化数据段和栈之间。

下图是一个典型的C程序内存布局:

memory-layout-of-a-c

需要注意的是:(1)除了上述段,一个C程序还包含一些其它段,比如符号表段、包含调试信息的段、包含动态共享库链接表的段等。但这些部分在程序执行时并不会作为进程映像的一部分被加载。(2)我们磁盘上的C程序文件只包括正文段和数据段,不包含bss段,因为程序运行的时候,会将bss段中的内容置为0.

我们可以使用size命令来查看正文段、数据段、bss段的大小,单位是字节:

allan@NYC:~$ size /usr/bin/gcc
text data bss dec hex filename
900519 8032 9696 918247 e02e7 /usr/bin/gcc

dec和hex列分别以十进制和十六进制显示了三个段的总大小。