学习总结与程序虚拟地址空间布局
前言
什么是进程虚拟地址盒子
程序运行起来,操作系统给这个进程提供一整块巨大的虚拟地址编号空间。 注意:这块只是地址编号,不是真实内存条(物理内存)。 进程看到的全部地址,全是虚拟地址。要访问真实数据,必须经过 MMU、页表转换成物理内存。 操作系统把这一整个大盒子,切割成多个功能不同的区域,也就是我们要学的「虚拟地址空间布局」。

整体空间分层
Linux 下 32 位程序,虚拟盒子从底部(低地址)到顶部(高地址)依次: .text代码段 → .data数据段 → .bss段 → 堆 → 栈。
最最顶端还有一块内核空间,用户代码完全不能触碰。
简单比喻: 盒子底部放程序代码、全局变量;中间是堆(malloc 用);盒子最顶上是栈(函数栈帧)。 堆往高处扩张,栈往低处扩张,两者互相朝对方靠近。
.text 代码段
.text存放程序编译完成后的机器指令,就是 CPU 一条一条执行的代码。 像"hello world"这种字符串字面量,也存放在这个区域。 本区域属性:只读。 如果代码强行尝试修改字符串字面量,程序直接崩溃(段错误)。
注意:这里不存放变量,只放指令与常量字符串。

.data 段
.data放在.text 的上方。 专门存放已经赋予初始值,并且初始值不是 0的全局变量、static 静态变量。
c
int g_a = 10;
static int s_a = 20;
g_a、s_a就放在.data 段。
要点:这些变量的值,编译的时候就确定,存放在 exe 可执行文件里面。程序运行,直接把值加载进内存。

.bss 段
.bss 在 .data 的上方。 专门存放没有初始化,或者初始值等于 0的全局变量、static 静态变量。
c
int g_b;
static int s_b = 0;
上面两个变量放在.bss 段。
重点特性: 磁盘上的 exe 可执行文件不存储一大堆 0,仅仅记录需要多大一块内存。 程序启动的时候,操作系统找到这块虚拟内存,全部自动置 0。

区分普通局部变量与static 局部变量
普通局部变量写在函数内部:
c
void test()
{
int a = 10; //普通局部变量
static int b = 10; //static局部变量
}
int a = 10;普通局部变量:放在栈上。函数调用开辟栈帧,函数结束栈帧销毁,变量直接消失。static int b = 10;static 局部变量:不在栈。有初值 10 →放到.data段;如果static int b;,放到.bss段。 static 变量生命周期是整个程序,函数退出不会销毁。

堆(Heap)
堆位于 .bss 的上方。 malloc、realloc、free全部操作堆这块虚拟地址空间。
关键要点(结合你之前做的考题):
- 堆向高地址方向增长。
- malloc 仅仅分配虚拟地址,不会立刻分配物理内存。
- 当代码第一次访问这块 malloc 出来的内存,触发缺页异常,操作系统才分配物理页框,建立虚拟‑物理映射。
- 堆内存需要程序员手动
free释放;忘记释放就产生内存泄漏。

栈(Stack)
栈处在用户虚拟空间的最高位置,就是前面学的函数栈帧所在区域。
- 栈向低地址方向增长。
- 保存:局部变量、函数参数、ebp、返回地址、寄存器现场。
- 由 CPU 自动管理:函数进入创建栈帧,函数结束销毁栈帧。不需要手动 free。
- 栈总大小固定。递归太深、局部数组太大,会栈溢出,程序崩溃。

磁盘 exe 文件 和 内存布局的区别
可执行 exe 是存放在硬盘上的文件。 当程序运行,操作系统把 exe 加载进虚拟内存,但磁盘文件布局 ≠ 内存布局。
.text、.data:磁盘 exe 里面保存真实数据,运行时拷贝到虚拟内存对应段。.bss:磁盘 exe 几乎不存数据,仅仅记录需要多大空间;程序启动,在虚拟内存开辟对应大小,操作系统直接全部填 0。- 堆、栈,磁盘 exe 里面完全不存在! 堆、栈是程序跑起来之后,操作系统在虚拟内存中新开辟出来的,exe 文件里没有堆和栈。

完整过程
回顾整套逻辑链:
- 程序运行,OS 给进程分配一整套虚拟地址,划分 text /data/bss / 堆 / 栈。
- exe 把 text、data 加载到虚拟内存;bss 只分配空间,运行时清零;堆、栈运行时新建。
- 此时以上所有区域,仅仅只有虚拟地址,并没有全部映射物理内存。
- CPU 访问某一块虚拟地址 → MMU 查页表。
- 如果没有对应物理页 → 触发缺页异常。
- 操作系统分配物理页框,建立映射,程序继续运行。
关键点:不管是访问栈局部变量、访问堆 malloc 内存、访问全局变量,只要第一次访问,都有可能触发缺页异常。

openEuler 是由开放原子开源基金会孵化的全场景开源操作系统项目,面向数字基础设施四大核心场景(服务器、云计算、边缘计算、嵌入式),全面支持 ARM、x86、RISC-V、loongArch、PowerPC、SW-64 等多样性计算架构
更多推荐

所有评论(0)