C语言内存布局

典型的C语言的内存分布由以下几块组成:
  • Test segment                               (文本段)
  • Initialzed data segment            (初始化数据段)
  • Uninitialized data segment        (未初始化数据段)
  • Stack                            (栈)
  • Heap                                (堆)

          (图a)
一:Text segment 文本段
     文本段,通常也被称为是代码段(code segment),简称text,一般包含实际要执行的代码(机器指令)
  作为内存中的一个区域,文本段通常被放置在堆和栈的下面,目的是防止堆或者栈溢出而导致文本段被修改(overwrite),也就是说,文本段是不可修改的。而且,它也是read-only,目的也是防止指令被修改。
  通常情况下,文本段是可以共享的,因此同一时间多个实例之前共享同一份文本段。


二:Initialized Data Segment 初始化数据段
  也通常被称为数据段,它是一个程序虚拟地址空间的一部分,通常包含了已经初始化好的全局变量和静态变量。
  需要注意的是:数据段并非只读的,很明显,变量的值在程序运行过程中是可以被改变的。
  C语言全局变量  const char* str = "hello";(data segment中)
       静态变量   static int i=10;(data segment中)


三:Uninitialized data segment        (未初始化数据段)
  通常被称为bss(block started by symbol),在程序执行前这个段中的数据会被内核初始化为0(这似乎是以前的一种做法,不是很明白)
  这个区域主要包含程序未初始化的全局变量,未初始化的静态变量。该段中的变量在执行之前初始化为0或NULL。
  比如:静态声明 static int i; 和 全局变量 int j; 由于没有初始化都将在BBS段

四:栈
  栈空间通常与堆空间紧邻,并且和堆空间的生长方向相反。如图a所示,stack由高地址区域向低地址区域生长,而heap区则相反,从低地址区域向高地址区域生长。当stack的指针到达了

  heap指针所在的位置时,也就意味这可用内存已经被耗尽了。(当然,随着内存地址增加和虚拟内存技术的发展,它们可以被放置在几乎任何地方,但生长方向仍然相反)
  stack包括了程序栈(LIFO),通常情况下在内存区域的高地址处。在x86的架构下,它向0地址处生长;在其他架构下它可能向其他方向生长。栈指针寄存器(stack pointer)记录栈顶地址,每次有值push进栈就会对栈指针进行修改。一个函数push进栈的一组值被称做堆栈帧(stack frame),堆栈帧保存有返回地址的最小的返回地址。

  栈中存放有自动变量和每次函数调用时的信息。每次函数调用返回地址,一些调用者环境信息(比如寄存器)都被存放在栈中。然后新调用的函数就在栈中为他们的 自动或者临时变量分配内存空间,这就是C中递归函数调用的过程。每次递归函数调用自己,新的堆栈帧就被创建,这样新的变量集合就不会被其他函数实例的变量 集合影响了。
  (可以参考http://blog.csdn.net/yang_yulei/article/details/45795591 ,写的很不错)
五:堆
  heap是动态内存,由用户管理。通过malloc/alloc/realloc申请空间,通过free释放所申请的空间。


example:

#include <stdio.h>
#include <stdlib.h>
 
int a;
static int b;
void func( void )
{
    char c;
    static int d;
}
int main( void )
{
    int e;
    int *pi = ( int *) malloc ( sizeof ( int ));
    func ();
    func ();
    free (pi );
    return (0);
}

 
程序中声明的变量a、b、c、d、e、pi的存储类别和生命期如下所述:
 
  •  a是一个未初始化的全局变量,作用域为整个程序,生命期是整个程序运行期间,在内存的bbs段
  • b是一个未初始化的静态全局变量,作用域为本源文件,生命期是整个程序运行期间,在内存的bbs段
  • c是一个未初始化的局部变量,作用域为函数func体内,即仅在函数体内可见,生命期也是函数体内,在内存的栈中
  • d是一个未初始化的静态局部变量,作用域为函数func体内,即仅在函数体内可见,生命期是整个程序运行期间,在内存的bbs段
  • e是一个未初始化的局部变量,作用域为函数main体内,即仅在函数体内可见,生命期是main函数内,在内存的栈中
  • pi是一个局部指针,指向堆中的一块内存块,该块的大小为sizeof(int),pi本身存储在内存的栈中,生命期是main函数内
  • 新申请的内存块在堆中,生命期是malloc/free之间

参考:

  • http://www.geeksforgeeks.org/memory-layout-of-c-program/
  • http://www.cnblogs.com/skynet/archive/2011/03/07/1975479.html
posted @ 2015-10-27 20:01  卡卡西sir  阅读(382)  评论(0编辑  收藏  举报