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

来源:互联网 发布:三维软件开发工具 编辑:程序博客网 时间:2024/05/17 03:39

本文转自 http://blog.chinaunix.net/uid-26548237-id-3818734.html

面是对可执行文件aa运行size命令后得到的结果。
     [root@xxx1 algriom]# size aa
    text      data    bss    dec    hex   filename
    1257    500     16   1773    6ed  aa
    其中:
    text:表示正文段大小,这是CPU执行的机器指令部分,通常,正文段是可共享的,所以即使是频繁执行的程序在存储器中也只需有一个副本;
    data:表示包含静态变量和已经初始化(可执行文件包含了初始化的值)的全局变量的数据段大小;
    bss :表示由可执行文件中不含其初始化值的全局变量组成,称之为未初始化数据段;
     
    PS:第4列和第5列是分别以十进制和十六进制表示的三个段的总长度。

    BSS段:BSS段(bss segment)通常是指用来存放程序中未初始化的全局变量的一块内存区域。BSS的英文是Block Started by Symbol的简称。BSS段属于静态内存分配。
    数据段:数据段(data segment)通过是指用来存放程序已经初始化的全局变量的一块内存区域。数据段属于静态内存分配。
    代码段:代码段(code segment/text segment)通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读,某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,比如字符串常量等。
    堆:堆(heap)是用于存放进程运行中动态分配的内存段,它的大小并不固定,可动态扩张或缩减。当进程调用malloc等函数分配内存的时候,新分配的内存就被动态添加到堆上(堆被扩张);当利用free等函数释放内存的时候,被释放的内存从堆中被剔除(堆被缩减)。
    栈:栈(stack)又称堆栈,是用户存放程序临时创建的局部变量,也就是我们函数括弧{}中定义的比变量(但不包括static声明的静态变量,static意味着在数据段中存放的变量)。除此之外,在函数被调用时,其参数也会被压入发起调用的进程栈中,并且等到调用结束后,函数的返回值也会被存放回栈中。由于栈先进后出的特点,所以栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。

[root@xxx1 algriom]# size aa
   text   data    bss    dec    hex filename
   1257    500     16   1773    6ed aa
    可以看到一个可执行程序在存储(没有调入内存)时分为代码段、数据区和未初始化数据区三部分。
    (1)代码区:也称之为正文段,这是存放CPU执行的机器指令。通常代码区是共享的,即其它执行程序可以调用它。代码段(code segment/text segment)通常是只读的,有些架构也允许自行修改。
    (2)数据区:存放已经初始化的全局变量、已经初始化的静态变量(包括全局和局部的)。
    (3)未初始化数据区(Block Started by Symbol,BSS)存放未初始化的
全局变量和未初始化的静态变量。BSS的数据在程序开始执行之前被初始化为0或NULL。
    代码区所在的地址空间最低,往上依次是数据区和BSS区,并且数据区和BSS区在内存中是紧挨着的。
    典型的存储器安排,入下图所示。
    
    text段和data段在编译时已经分配了空间,而BSS段并不占用可执行文件的大小,它是由链接器来获取内存的。
    bss段(未进行初始化的数据)的内容并不存放在磁盘上的程序文件中。其原因是内核在程序开始运行前将它们设置为0。需要存放在程序文件中的只有正文段和初始化数据段。
    data段(已经初始化的数据)则为数据分配空间,数据保存到目标文件中。

    数据段包含经过初始化的全局变量以及它们的值。BSS段的大小从可执行文件中得到,然后链接器得到这个大小的内存块,紧跟在数据段的后面。当这个内存进入程序的地址空间后全部清零。包含数据段和BSS段的整个区段此时通常称为数据区。

    可执行程序在运行时又多出两个区域:栈区和堆区。
    (4)栈区:由编译器自动释放,存放函数的参数值、局部变量等。每当一个函数被调用时,该函数的返回类型和一些调用的信息被存放到栈中。然后这个被调用的函数再为他的自动变量和临时变量在栈上分配空间。每调用一个函数一个新的栈就会被使用。栈区是从高地址位向低地址位增长的,是一块连续的内存区域,最大容量是由系统预先定义好的,申请的栈空间超过这个界限时会提示溢出,用户能从栈中获取的空间较小。
    (5)堆区:用于动态分配内存,位于BSS和栈中间的地址区域。由程序员申请分配和释放。堆是从低地址位向高地址位增长,采用链式存储结构。频繁的malloc/free造成内存空间的不连续,产生碎片。当申请堆空间时库函数是按照一定的算法搜索可用的足够大的空间。因此堆的效率比栈要低的多。

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

    举个例子说明各种变量存在什么区:

  1. int a=0;//a在全局已初始化数据区

  2. char *p1;//p1在BSS区(未初始化全局变量)

  3. main()

  4. {

  5.     int b;//b为局部变量,在栈区

  6.     char s[]="abc";//s为局部数组变量,在栈区

  7.     //"abc"为字符串常量,存储在已初始化数据区

  8.     char *p1,*p2;//p1,p2为局部变量,在栈区

  9.     char *p3="123456";//p3在栈区,123456\0在已初始化数据区

  10.     static int c=0;//c为局部(静态)数据,在已初始化数据区

  11.     //静态局部变量会自动初始化(因为BSS区自动用0或NULL初始化)

  12.     p1=(char*)malloc(10);//分配得来的10个字节的区域在堆区

  13.     p2=(char*)malloc(20);//分配得来的20个字节的区域在堆区

  14.     free(p1);

  15.     free(p2);

  16.     p1=NULL;//显示地将p1置为NULL,避免以后错误地使用p1

  17.     p2=NULL;

  18. }

   结论:

    1 经过初始化的全局变量和静态变量保存在数据段中。

    2 未经初始化的全局变量和静态变量保存在BSS段。

    3 函数内部声明的局部变量保存在堆栈段中。

    4 const修饰的全局变量保存在文本段中,const修饰的局部变量保存在堆栈段中。

    5 字符串常量保存在文本段中。


0 0
原创粉丝点击