博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C程序的内存分布
阅读量:4070 次
发布时间:2019-05-25

本文共 3518 字,大约阅读时间需要 11 分钟。

目录


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 
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 
int global; //未初始化数据段BSSint 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 
int global; //未初始化数据段BSSint 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 
int global; //未初始化数据段BSSint 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 
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

 

你可能感兴趣的文章
linux中时间精度的获取问题
查看>>
cancel_rearming_delayed_workqueue 函数使用的一个小备注
查看>>
使用LOGFONT修改windows sdk下字体为系统字体
查看>>
wind32 sdk下修改控件的字体
查看>>
c列举文件目录
查看>>
解决MFC下线程创建的一个编译错误
查看>>
在HW这四个月
查看>>
最近的生活
查看>>
freemarker下的一个错误的解决
查看>>
MFC的一些记录
查看>>
MFC的一些记录
查看>>
MFC中给应用程序添加托盘支持
查看>>
MFC上显示GIF图片(使用 GIF Animation Control控件)
查看>>
MFC中时间显示
查看>>
MFC DLL的一些知识
查看>>
easyUI的布局入门
查看>>
vsftp下的一个小错误
查看>>
jdbc查询超大数据集内存溢出
查看>>
acegi的一个异常错误
查看>>
java实现的KMP算法
查看>>