C程序的内存分布

目录

1.C程序内存分布

2.示例详解

2.1查看内存分布

2.2未初始化全局变量

2.3未初始化静态变量

2.4已初始化静态变量

2.5初始化全局变量


1.C程序内存分布

一个典型的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(已初始化数据段)
    
已初始化数据段,通常简称为数据段。包括一个程序中已经被初始化过的全局变量以及静态变量。
    注意:数据段不是只读的,因为变量值在运行过程中可能会被更改。
    数据段可以进一步分为已初始化的只读区,以及已初始化的读写区。

    示例1:C程序中的全局字符串 char s[] = "hello world",以及main函数之外的C声明debug=1,都将存储在读写区。

    示例2:const char *string = "hello world", 一个全局的C声明,会使得字符串"hello world"存储在只读区,指针string存储在读写区。

    示例3: 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, 和free管理,可能会使用系统调用brk和sbrk来调整大小(注意,brk/sbrk和一个单独的堆区并不一定等价于malloc/realloc/free, 它们也可能使用mmap来预留虚拟内存的潜在非连续区域,加入到进程的虚拟地址空间中)。
    在一个进程中,堆区在所有的共享库之间共享,并动态地加载模块。

2.示例详解

以下所有例子都运行在环境: CentOS7.2 + gcc4.8.5

2.1查看内存分布

    Linux上的size(1)命令可以查看text, data以及BSS段的大小(字节为单位)。

#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
   1129  540   4     1673   689   memoryLayout

2.2未初始化全局变量

#include <stdio.h>
int global; //未初始化数据段BSS
int 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  548    12   1789    6fd    memoryLayout

bash-4.1$ ./memoryLayout
&global=0x601038

由上可知,未初始化全局变量,确实处于BSS段中。

2.3未初始化静态变量

#include <stdio.h>
int global; //未初始化数据段BSS
int 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
   1279  548    12   1839    72f    memoryLayout

bash-4.1$ ./memoryLayout
&global=0x60103c
&localStatic=0x601038

2.4已初始化静态变量

#include <stdio.h>
int global; //未初始化数据段BSS
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
   1279  552    8     1839    72f    memoryLayout

bash-4.1$ ./memoryLayout
&global=0x60103c
&localStatic=0x601034

2.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
   1279  556    4     1839    72f    memoryLayout

bash-4.1$ ./memoryLayout
&global=0x601034
&localStatic=0x601038

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值