C语言的内存布局

一个典型C程序的的内存表达包括如下部分:

1. 文本段

2. 初始化数据段

3. 未初始化数据段

4. 栈区

5. 堆区


一个运行进程的典型的内存布局

1. 文本段

一个文本段,也被称作代码段或者简称为文本,是一个程序在对象文件或者在内存中的其中一部分,包含可执行的指令。

在内存区,文本段可能放在堆区或者栈区的下面,这主要是为了防止堆或栈的溢出从而覆盖它。

通常情况下,文本段是共享的,这样使得为了频繁执行的程序在内存中仅仅只需要一个拷贝,例如文本编辑器,C编译器,shell等等。另外,文本段通常是只读的,主要是为了防止程序被不小心地更改它的指令。

2. 初始化数据段

初始化数据段,通常也被称为数据段。数据段是一个程序的虚拟地址空间的一部分,它包含着被程序员初始化的全局变量和静态变量。

注意,数据区并不是只读的,因为它的值可以在运行时被改变。

这个段又可以进一步被分为初始化只读区和初始化读写区。

例如,在C中被定义为全局变量的char s[] = "hello world"和位于main(也就是全局的)以外的语句int debug=1,会被存储在初始化读写区。一个全局C语句,比如const char* string = "hello world",会将字符串值"hello world"存储在初始化只读区,而字符指针变量则会被存储在初始化读写区。

例如:static int i = 10,将会存储在数据区,同样,global int i = 10也会存储在数据区。

3. 未初始化数据段

未初始化数据段,经常被称为"bss"数据段,它以一个古老的汇编器运算符代表着"block started by symbol"来命名。在程序开始执行之前,这个段中的数据会被内核初始化为0。

未初始化段起始于起始于数据段的结尾,并且包含所有的全局变量和静态变量,这些变量会被初始化为0,而且没有在源代码中有显示地进行初始化操作。

例如一个变量声明为static int i;会被存放在BSS段。

再比如一个全局变量声明为int j;也会被存放在BSS段。

4. 栈

传统上栈区和堆区是紧邻的,但是增长方向相反;当栈的指针遇到了堆的指针,则表明空闲的内存被耗尽了。(在现代大地址空间和虚拟内存技术下,它们可能被放在任意的位置,但是它们的增长方向仍然是典型的相反。)

栈区包含程序栈,就是LIFO结构,典型地是位于内存的高地址部分。在标准的X86计算机架构下,它朝着地址为0的方向增长;在一些其它的架构下,它朝着相反的方向增长。一个“栈指针”寄存器跟踪栈的顶点,每次一个新的值压到栈中,该指针跟着进行调整。为了一个函数的调用而压进的值的集合称为“栈帧”;一个栈帧包含最小的返回地址。

自动变量和每一次函数被调用所保存的信息都存放在栈中。每一次函数被调用,返回的地址以及关于调用者环境的特定信息,比如一些机器寄存器,都会保存在栈中。新的调用的函数然后为其自动和临时变量在栈上分配空间。这就是在C语言中递归函数工作的原理。每一次递归函数调用它自己时 ,就会用到一个新的栈帧,所以一个变量的集合不会影响到该函数的其它实例的变量。

5. 堆

堆通常是动态内存申请所在的段。

堆区起始于BSS段的终点,并向着地址增大的方向增长。堆区通过malloc,realloc和free函数进行管理,可能会用到brk和sbrk系统调用来调整它的大小(注意brk/sbrk的使用和一个单一的“堆区”并不需要满足malloc/realloc/free的要求;它也可以通过使用mmap来实现逆转潜在的虚拟内存的非连续区域到进程的虚拟地址空间)。在一个进程中所有的共享库和动态加载模块共享堆区。

实例:

size(1)命令报告出文本段,数据段,和bss段的大小(以bytes为单位)(为了更深入的了解,请参考size(1)的man page)

1. 检查如下简单地C程序

#include <stdio.h>
int main(void)
{
    return 0;
}

fengxi@ubuntu:~/C/memeory$ size memory-layout
   text   data   bss   dec   hexfilename
   1033    276     4  1313   521memory-layout

2. 让我们在程序中增加一个全局变量,然后再来检查bss的大小

#include <stdio.h>
 
int global; /* Uninitialized variable stored in bss*/
 
int main(void)
{
    return 0;
}

fengxi@ubuntu:~/C/memeory$ size memory-layout
   text   data   bss   dec   hexfilename
   1033    276     8  1317   525memory-layout

3. 让我们增加一个静态变量,也是存储在bss中。

#include <stdio.h>

int global; /* Uninitialized variable stored in bss */

int main(void)
{
    static int i; /* Uninitialized static variable stored in bss */
    return 0;
}
fengxi@ubuntu:~/C/memeory$ size memory-layout
   text   data   bss   dec   hexfilename
   1033    276   12  1321   529 memory-layout
4. 让我们初始化静态变量,它将会存储在数据段中。

#include <stdio.h>

int global; /* Uninitialized variable stored in bss */

int main(void)
{
    static int i = 100; /* Uninitialized static variable stored in bss */
    return 0;
}
fengxi@ubuntu:~/C/memeory$ size memory-layout
   text   data   bss   dec   hexfilename
   1033    280     8  1321   529memory-layout
5. 让我们初始化全局变量,也将被存储在数据段中。

#include <stdio.h>

int global = 10; /* Uninitialized variable stored in bss */

int main(void)
{
    static int i = 100; /* Uninitialized static variable stored in bss */
    return 0;
}
fengxi@ubuntu:~/C/memeory$ size memory-layout
   text   data   bss   dec   hexfilename
   1033    284     4  1321    529memory-layout

此文翻译自 这里

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值