C程序的内存布局

一个典型的C程序内存表现组成应该有以下几个部分:

  1. 代码段/文本段(Text segment)
  2. 初始化数据段(Initialized data segment or Data segment)
  3. 未初始化数据段(Uninitialized data segment or bss)
  4. 栈(Stack)
  5. 堆(Heap)
一段运行的C程序典型的内存分布

1. 代码段(Text segment)

代码段(也成为文本段)是目标文件或者内存中的一个部分(段)。它包含着可执行指令。

作为内存区域,代码段可以放在堆或者栈的下面,以防止堆和栈溢出时覆盖它。

通常,文本段是可共享的,因此对于经常执行的程序(如文本编辑器、C编译器、shell等),只需要在内存中保存一个副本。此外,文本段通常是只读的,以防止程序意外地修改其指令。

2. 初始化数据段(Initialized data segment)

初始化的数据段,通常简称为数据段(Data segment)。数据段是程序虚拟地址空间的一部分,它包含由程序员初始化的全局变量和静态变量。

注意,数据段不是只读的,因为变量的值可以在运行时被更改。

该段可以被进一步分为(初始化的)只读区域和(初始化的)可读写区域。

例如,由C程序中定义的全局字符串char s[]=“hello world”和一句在 main 之外的C语句,如int debug=1(即全局变量global variable)将存储在初始化的读写区域中。而像全局变量 const char*string=“hello world” 这样的C语句,其字符串文本“hello world”存储在初始化只读区域,而字符指针变量字符串存储在初始化读写区域。

例:静态变量 (如static int i = 10)存储在数据段中,全局变量(如int i = 10)也存储在数据段中。

未初始化数据段(Uninitialized data segment or BSS)

未初始化的数据段,通常称为“bss”段,是早期汇编程序运算符“block started by symbol”的缩写。在程序开始执行之前,内核将该段中的数据初始化为算术0。

未初始化的数据(bss)从数据段(初始化的数据段)的末尾开始,包含所有初始化为零或在源代码中没有显式初始化的全局变量和静态变量。

例如,声明为 static int i 的静态变量 i 将包含在BSS段中。声明为 int j 的未初始化全局变量 j 将包含在BSS段中。

栈(Stack)

栈区域传统上与堆区域相邻,并朝相反的方向增长。当栈指针遇到堆指针时,可用内存耗尽。(随着现代的大地址空间和虚拟内存技术的发展,它们可以被放置在几乎任何地方,但它们通常还是朝相反的方向发展。)

栈区域包含程序栈,一种通常位于内存的较高部分的后进先出(LIFO)的数据结构。在标准的PC x86计算机体系结构上,它向地址零方向增长。在其他一些体系结构上,它向相反的方向增长。“栈指针”寄存器跟踪栈的顶部。每次将值置入栈(push)时都会对其进行调整。函数调用时置入(push)栈的数值集合(set of values)称为“栈帧”(stack frame)。栈帧至少包含一个返回地址。

栈用来存储自动变量(automatic variables),以及每次调用函数时需要保存的信息。每次调用函数时,要返回的地址和调用方环境的某些信息(如某些计算机寄存器)都保存在栈中。然后,新调用的函数在栈上为其自动变量和临时变量分配空间。这就是C中递归函数的工作原理。每次递归函数调用自身时,都会使用一个新的栈帧(stack frame),因此不同函数调用间的实例的变量并不会相互影响。

堆(Heap)

动态分配的内存就在堆区。

堆区域从BSS段的末尾开始向高地址方向生长。堆区域由malloc、realloc和free管理,malloc和free可以使用brk和sbrk系统调用来调整其大小。堆区域内容被进程中的所有共享库和动态加载的模块共享。

例子

size命令可以统计text,data,和bss段的大小,单位为bytes。

  1. 我们编译下面这个简单的例子,并查看其目标文件:
#include <stdio.h> 
  
int main(void) 
{ 
    return 0; 
} 
  1. 让我们在上面的程序中加入一个全局变量。接着我们看下bss段大小的变化(标红):
#include <stdio.h> 
  
int global; /*未初始化的变量存贮在bss段*/
  
int main(void) 
{ 
    return 0; 
} 
  1. 让我们加一个未初始化的静态变量(static variable):
#include <stdio.h> 
  
int global; /* Uninitialized variable stored in bss*/
  
int main(void) 
{ 
    static int i; /* Uninitialized static variable stored in bss */
    return 0; 
} 
  1. 让我们初始化静态变量。这样会使得静态变量被存贮在数据段(data segment):
#include <stdio.h> 
  
int global; /* Uninitialized variable stored in bss*/
  
int main(void) 
{ 
    static int i = 100; /* Initialized static variable stored in DS*/
    return 0; 
} 
  1. 让我们初始化全局变量。同样,该变量将会被存到数据段:
#include <stdio.h> 
  
int global = 10; /* initialized global variable stored in DS*/
  
int main(void) 
{ 
    static int i = 100; /* Initialized static variable stored in DS*/
    return 0; 
} 

参考

Memory Layout of C Programs

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 159,835评论 4 364
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,598评论 1 295
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 109,569评论 0 244
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,159评论 0 213
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,533评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,710评论 1 222
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,923评论 2 313
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,674评论 0 203
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,421评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,622评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,115评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,428评论 2 254
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,114评论 3 238
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,097评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,875评论 0 197
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,753评论 2 276
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,649评论 2 271