说明:

  1. Linux系统下编译产生的二进制程序是以ELF格式存储的,ELF格式是分段的;Linux系统采用段式内存管理架构,二进制程序加载进内存后内存分布也是分段的。
  2. windows系统也是类似的。

个人理解:

  1. 分段是由编译器和操作系统实现,编译时编译器将不同类型的元素存储到相应的段,以区分处理,利于管理和加快操作效率。
  2. 分段行为不是固定的,不同编译器,不同平台可能有细微差别,虚拟内存和硬盘都是连续的。
  3. 程序由数据和处理两部分组成,处理部分(代码)编译后为二进制指令(代码段)比较固定,而数据部分(变量)有多种形式,例如:全局变量,局部变量,static变量,const变量等等,为了实现这些需求和加快操作效率,因此数据段有多种分段类型。

一、代码:

  1. 段名:代码段(text段)
  2. 编译后生成给CPU执行的机器指令,一个程序只有一个代码段,只读,防止程序由于意外事故而修改自身指令。
  3. 该段也有可能包含一些只读的常量,例如字符串常量,const修饰的变量(各种单片机的编译器会这样存储),由编译器决定。

变量:

全局变量(生命周期等于整个程序执行期)

  1. 全局变量在编码时已经固定了,占用内存大小和值已确定,因为这些特性,全局变量可以在编译时就准备好,不需要等到运行时再去逐个分配内存设置值。
  2. 这里说的全局变量包括 全局变量,static的全局变量,static的局部变量。
  3. 全局变量由于初始值的不同,有以下两种情况。

二、已赋不为0的初始值:

  1. 段名:已初始化数据段(data段
  2. 初值不为0,编译器简单处理认为数据都不同,需要逐个变量保存到二进制程序文件中,程序运行时直接将整段数据拷贝进内存。
  3. 个人理解:编译器可以进一步优化,相同的值可以只存一份。
  4. 该段保存了程序中所有赋了初值并且初值不为0的全局变量,包括全局变量,static的全局变量,static的局部变量。
  5. 如果该段数据较多,会导致程序二进制文件非常大,如下:
int ar[300000] = {1};        //将全部存储在data段,虽然值都是一样的
static int a = 10; //保存在data段
void test(){
static int b = 10;
}

三、未赋初值或者初值为0:

    1、段名:未初始化数据段(bss段)。

    2、由于可以将这些变量的初值处理成一样的,都设置为0,二进制程序文件就没必要存储这些值,只需要记录该段的首地址和段长度,程序运行加载进内存时再按这些参数申请和格式化内存就好。

    3、该段保存程序中没有进行初始化或者初始化为0的全局变量;例如:

int a; 
int b = 0;
static int a;
static int a = 0;
void test(){
static int b;
static int b = 0;
}

四、局部变量(生命周期由系统控制)

    1、段名:栈。

    2、由于局部变量不是固定的,无法在编译时进行处理。

    3、 增长方向:自顶向下增长;普通的局部变量以及每次函数调用时所需要保存的信息(返回地址;环境信息)。

    4、栈变量最大的特征是:栈变量都应该是临时变量,出栈后内存就非常可能被覆盖。

五、动态变量(生命周期由程序员控制)

   1、段名:堆。

   2、该段的大小并不固定,可动态扩张或缩减。

   3、因为动态变量并不是固定的,无法在编译时进行处理。

   4、动态存储区,是向高地址扩展的数据类型,是自下向上的扩展方式,动态内存分配的内存区域。

   5、堆变量最大的特征是:大内存变量或者永久变量,临时小内存变量不应该放在堆内存中,应该放在栈内存中。

六、只读变量

  1、段名:只读变量区域(rodata段)

  2、只读的内存区域,const修饰的常量,以及常量字符串保存在该区域。例如:

const int a = 100; 
char *b = "hello world"。 //hello world保存在该段,但是变量b不是。

存储时形态:

    二进制程序中不包含堆,栈需要动态管理的段,程序加载进内存才会产生。

运行时形态:

   1、每个进程都独自拥有4GB的虚拟内存空间,使用时再由系统转换成物理内存地址,该转换对用户是透明不可见的,因此时常讲的内存空间都是虚拟内存空间。

   2、程序的代码段和一些全局变量是固定的,不会改变的,编译时会将代码段和这些变量的虚拟内存地址确定,因此每次运行都是固定的。

   3、Linux下C程序的内存分布图如下,C程序将内存分为以下5部分,地址从低到高排列:

Linux下可执行程序的分段_服务器