程序内存布局中,Text、Data、BSS、Heap与Stack如何构成一串的?
摘要:本文围绕程序运行时的内存布局进行了介绍,对典型 C 程序在进程虚拟地址空间中的结构进行了梳理。文章首先说明了程序运行时内存划分的基本形式,指出一个典型程序通常由代码段(Text Segment)、数据段(Data Segment)、BSS
一、程序运行时的内存模型
在现代计算机系统中,程序运行时并不是直接操作物理内存,而是运行在进程虚拟地址空间中。操作系统为每个进程提供一块独立的地址空间,并按照程序运行的需求将其划分为多个逻辑区域,用于存储不同类型的数据。这种划分并不是物理内存结构,而是一种按照数据用途与生命周期进行的逻辑划分。在典型的C/C++程序中,进程地址空间通常包含以下几个区域:
代码段(Text Segment)
数据段(Data Segment)
BSS段
堆(Heap)
栈(Stack)
二、程序地址空间整体结构
典型的程序虚拟地址空间结构如下:
各个区域在运行过程中具有不同的增长方向与管理方式:
Stack:从高地址向低地址增长
Heap:从低地址向高地址增长
Text/Data/BSS:固定大小
这里需要注意一个点,就是堆和栈在运行过程中可能相向增长。
三、代码段(Text Segment)
代码段用于存放程序编译之后生成的机器指令。编译器在对源代码进行编译时,会将每一个函数转换为对应的机器指令序列,这些指令最终都会被放入代码段中,当程序被加载到内存并开始运行时,CPU从代码段中读取指令并按照顺序执行,从而完成程序逻辑。因此,从程序执行的角度来看,代码段实际上就是程序真正被处理器执行的部分。
以C语言为例,当定义一个普通函数时:
void func(void)
{
printf("Hello world!\n");
}
在编译阶段,编译器会将该函数转换为一系列具体的机器指令,例如函数入口、参数准备、函数调用以及函数返回等指令。这些指令在链接阶段会被统一放入程序的代码段中。当程序运行时,CPU通过程序计数器(Program Counter)逐条读取这些指令并执行,因此函数的执行本质上就是处理对代码段中机器指令的顺序解释和执行过程。
代码段通常被设置为只读且可执行的内存区域,之所以设置为只读,一方面是为了防止程序在运行过程中意外修改自己的指令,从而导致不可预测的行为;另一方面也是处于系统安全性的考虑,如果代码段可以随意写入,就可能被恶意代码篡改,从而改变程序的执行逻辑。现代操作系统通常会对代码段设置“只读 + 可执行”的访问权限,即允许处理器读取并执行其中的指令,但不允许对其进行写操作。
从生命周期上看,代码段在程序加载时就已经被映射到进程的地址空间中,并且在整个程序运行期间保持不变。程序结束后,操作系统会回收这部分内存。因此与堆或栈这种运行时会动态变化的区域不同,代码段的大小和内容在程序编译完成后基本就已经确定。
在一些支持虚拟内存管理的操作系统中,如果多个进程运行的是同一个程序,它们的代码段还可以被操作系统共享。例如多个进程同时运行同一个可执行文件时,系统通常只需要在物理内存中保存一份代码段,而在每个进程的虚拟地址空间中映射到这同一份物理内存。这样既可以节省内存,也不会影响程序的独立运行,因为代码段本身只是只读的,各个进程不会相互修改其中的内容。
四、数据段(Data Segment)
数据段用于存放已经初始化的全局变量和静态变量。这类变量在程序开始运行之前就已经具有确定的初始值,因此在程序加载阶段,操作系统或运行时环境会将这些初始值一并加载到内存中。换句话说,就是当程序真正开始执行时,这些变量就已经处于初始化完成的状态,可以被程序直接访问和修改
比如在C语言中:
int global_var = 10;
static int counter = 5;
global_var 和 counter 都属于已初始化的全局或静态变量,因此它们会被放入数据段中。编译器在生成可执行文件时,会将这些变量的初始值一起写入可执行文件的对应区域。当程序被加载到内存时,这些初值会被拷贝到进程地址空间中的数据段区域,从而保证程序运行时变量已经处于正确的初始状态。
数据段中的变量具有比较明确的生命周期:它们在程序启动时被创建,在整个程序运行过程中始终存在,并且只有在程序结束时才会被系统回收。因此,与栈中的局部变量不同,数据段中的变量不会随着函数调用结束而销毁,而是贯穿程序运行的整个周期。
需要注意的是,数据段主要针对的是已初始化的全局变量和静态变量。如果全局变量或静态变量在定义时并没有给出初始值,则通常不会被放入数据段,而是会进入另一块专门用于存储未初始化变量的区域,即 BSS段。这种划分的主要目的在于减少可执行文件的体积,因为未初始化变量在文件中只需记录其大小,而不需要存储具体的数据内容。
五、BSS段
BSS段用于存放未初始化的全局变量和静态变量。
