C程序的内存分布

来源:互联网 发布:南方全站仪pts数据 编辑:程序博客网 时间:2024/04/30 08:42

1. 一个典型的C程序的内存布局包含下面几个部分:

1) Text segment/Code segment (文本/代码段)
2) Initialized data segment (已初始化数据段)
3) Uninitialized data segment/BSS(Block Started by Symbol) (未初始化数据段)
4) Stack (栈)
5) Heap (堆)


一个正在运行的进程的典型内存分布
1. Text Segment/Code Segment(文本/代码段):
文本段,也称之为代码段或者文本,它是一个程序内存的一部分,包含可执行指令。
做为一块内存区域,文本段一般处于堆/栈之下,已防止堆/栈将其内存覆盖了。
通常文本段是可以共享的,这样对于需要经常执行的程序,只需要一份copy存在与内存中,例如文本编辑器,C编译器,shell等。另外,文本段一般是只读的,防止外边程序修改其指令。
2. Initialized Data Segment(已初始化数据段):
已初始化数据段,通常简称为数据段。包含一个程序中已经被初始化过的全局变量以及静态变量。
注意,数据段不是只读的,因为变量值在运行过程中可能会被更改。
数据段可以进一步分为已初始化的只读区,以及已初始化的读写区。

例如,C程序中的全局字符串 char s[] = "hello world",以及main函数之外的C声明debug=1,都将存储在读写区。一个全局的C声明,例如const char *string = "hello world", 会是的字符串"hello world"存储在只读区,指针string存储在读写区。
例如:
static int i = 10;
全局的int i = 10;
3. Uninitialized Data Segment/BSS (未初始化数据段):
未初始化数据段,常称为"BSS"段。已一个古老的汇编语言操作符命名,表示"block started by symbol". 这个段里边的数据会在程序开始执行前被内核初始化为算术0.
BSS段位于(初始化)数据段之后,包含所有的全局变量,以及初始化为0或者没有被显示初始化的静态变量。

例如:
static int i;
全局的int j;
4. Stack:
栈区通常是与堆区相邻的,并且是相反方向增长;当栈指针与堆指针重合时,表示剩余内存已经全部耗尽(在现代的大内存空间和虚拟内存技术的背景下,栈内存可能任意分配,但是总体上任然是反方向增长)。
栈区包含程序栈,是一个LIFO结构,通常位于内存的高地址部分。在通常的x86架构体系中,往地址0方向增长;在其他的一些架构中,往反方向增长。一个“栈指针"指向栈顶;每次当push一个值到栈中时,栈指针会调整。压入一个函数调用的所有的值称为一个”栈帧";一个"栈帧"至少包含一个返回地址。
栈用于存储自动变量,函数每一次调用的值都存储在其中。每次函数被调用,返回地址以及调用者的环境信息(如某些寄存器)会被存储在栈中。新调用函数会在栈中为期自动变量以及临时变量分配内存。这就是C中递归函数能工作的原因。每次一个递归函数调用自己,一个新的栈帧会被使用,这样本地调用中的变量值不会干扰下一次的调用。
5. Heap:
堆通常用于动态内存管理。
堆开始与BSS段末尾,并且往高地址增长。堆内存由malloc, realloc, and free管理,可能使用系统调用brk和sbrk来调整大小(注意,brk/sbrk和一个单独的堆区并不一定等价于malloc/realloc/free, 它们也可能使用mmap来预留虚拟内存的潜在非连续区域,加入到进程的虚拟地址空间中)。在一个进程中,堆区在所有的共享库之间共享,并动态地加载模块。

2. 例子说明

以下所有例子都运行在环境: RHEL6.5 + gcc4.8.1
Linux上的size(1)命令可以查看text, data以及BSS段的大小(字节为单位)。
1. 查看下面简单C程序的内存
#include <stdio.h>int main(void){    return 0;}
bash-4.1$ gcc memoryLayout.c -o memoryLayout
bash-4.1$ size memoryLayout
   text   data bss  dec    hex   filename
   1116 496   16  1628   65c   memoryLayout

2. 添加一个全局变量

#include <stdio.h>int global; //未初始化数据段BSSint main(void){    printf("&global=%p", &global);    return 0;}
bash-4.1$ gcc memoryLayout.c -o memoryLayout
bash-4.1$ size memoryLayout
   text   data  bss  dec     hex    filename
   1229 504    24  1757    6dd    memoryLayout
bash-4.1$ ./a.out &global=0x6008e8

3. 添加一个静态变量

#include <stdio.h>int global; //未初始化数据段BSSint main(void){    static int localStatic; //未初始化静态变量BSS    printf("&global=%p\n", &global);    printf("&localStatic=%p\n", &localStatic);    return 0;}

bash-4.1$ gcc memoryLayout.c -o memoryLayout

bash-4.1$ size memoryLayout
   text    data     bss     dec     hex     filename   1278     504      24    1806   70e     memoryLayout 
bash-4.1$ ./a.out 
&global=0x60091c&localStatic=0x600918

4. 初始化添加的这个静态变量

#include <stdio.h>int global; //未初始化数据段BSSint main(void){    static int localStatic = 100; //已初始化静态变量,存储在数据段    printf("&global=%p\n", &global);    printf("&localStatic=%p\n", &localStatic);    return 0;}

bash-4.1$ gcc memoryLayout.c -o memoryLayout

bash-4.1$ size memoryLayout   text    data     bss     dec       hex   filename   1278     508      24    1810     712   memoryLayout
bash-4.1$ ./a.out 
&global=0x600920
&localStatic=0x600908

5. 初始化全局变量

#include <stdio.h>int global = 99; //初始化的全局变量,存储在数据段int main(void){    static int localStatic = 100; //初始化的静态变量,存储在数据段    printf("&global=%p\n", &global);    printf("&localStatic=%p\n", &localStatic);    return 0;}

bash-4.1$ gcc memoryLayout.c -o memoryLayout

bash-4.1$ size memoryLayout   text    data     bss     dec     hex filename   1278     512      16    1806     70e memoryLayout
bash-4.1$ ./a.out 
&global=0x600908
&localStatic=0x60090c

0 0
原创粉丝点击