news 2026/5/21 8:49:11

【程序地址空间:进程眼中的“超级大饼”】

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【程序地址空间:进程眼中的“超级大饼”】

虚拟地址空间、页表、写时拷贝、mm_struct——一篇讲透进程如何“独占”内存

文章目录


前言

你有没有想过这些问题?

如果你对这些问题的答案模模糊糊,那这篇文章就是为你准备的。我们把虚拟地址空间页表映射写时拷贝等核心概念,一次性讲清楚。

🎯 一句话:操作系统给每个进程画了一张“超级大饼”,让进程以为自己独占物理内存,实际上背后有页表在偷偷映射。


一、一个进程,一个虚拟地址空间

在 Linux 中,每个进程都拥有自己独立的虚拟地址空间(通常 32 位系统是 4GB,64 位系统更大)。这个地址空间是“虚拟”的,不是真实的物理内存。

概念说明
虚拟地址空间进程“认为”自己拥有的内存地址范围
物理内存计算机上真实的内存条

🥞 比喻:每个进程就像一个孩子,操作系统像一位爸爸。爸爸给每个孩子画了一张巨大的“大饼”(虚拟地址空间),告诉他们:“这块饼全是你的!”但实际上,爸爸只有一张真实的饼(物理内存),只是切成了小块分给孩子们。每个孩子都以为自己拥有整张饼。


二、页表:虚拟地址到物理地址的“翻译官”

2.1 页表是什么?

页表是操作系统为每个进程维护的一张映射表,用来将虚拟地址转换为物理地址

虚拟地址 ──(页表)──> 物理地址

2.2 映射关系

初始情况下,父进程和子进程的页表映射关系是一样的。也就是说,同一个虚拟地址在父子进程中映射到同一个物理页面。

🧬 比喻:页表就像一张地图。进程拿着虚拟地址(比如“王府井大街1号”),通过地图找到真实的物理位置(比如“北京市东城区……”)。

通过下面这张图,希望你能更加理解


三、写时拷贝(Copy-on-Write):独立性的实现

3.1 什么是写时拷贝?

当父子进程共享同一块物理内存时,如果子进程(或父进程)要对这块内存进行修改,操作系统会:

  1. 在物理内存中开辟一块新空间
  2. 将原来的内容拷贝到新空间
  3. 修改子进程的页表映射,让子进程的虚拟地址指向新空间
  4. 父进程的映射保持不变

结果:父子进程的虚拟地址相同,但物理地址不同,实现了进程的独立性

3.2 为什么要写时拷贝?

原因说明
减少创建时间fork 时不需要拷贝全部内存,只需复制页表
减少内存浪费只有修改时才真正拷贝,否则一直共享

💡 如果没有写时拷贝,fork 一个进程就要把父进程的所有内存拷贝一遍,既慢又浪费内存。

3.3 写时拷贝流程示意

┌─────────────────────────────────────────────────────────┐ │ fork 之后(初始状态) │ │ 父进程虚拟地址 V ──页表──> 物理页面 P │ │ 子进程虚拟地址 V ──页表──> 物理页面 P(相同) │ └─────────────────────────────────────────────────────────┘ │ │ 子进程尝试写入 ▼ ┌─────────────────────────────────────────────────────────┐ │ 写时拷贝后 │ │ 父进程虚拟地址 V ──页表──> 物理页面 P(不变) │ │ 子进程虚拟地址 V ──页表──> 物理页面 P'(新拷贝) │ └─────────────────────────────────────────────────────────┘

🎯核心:虚拟地址不变,但页表映射变了,物理地址变了。


四、虚拟地址空间的本质:一个数据结构

4.1 要不要管理“大饼”?

要管理!操作系统用struct mm_struct这个数据结构来描述虚拟地址空间。

概念说明
虚拟地址空间操作系统给进程画的“饼”
mm_struct描述虚拟地址空间的内核数据结构

🧠 经典思想:先描述,再组织。操作系统用mm_struct描述每个进程的地址空间,再用链表或红黑树组织起来。

4.2 虚拟地址空间的区域划分

虚拟地址空间不是铁板一块,而是划分成多个区域。每个区域有起始地址和结束地址。

区域典型位置内容
代码段低地址程序指令
数据段代码段上方已初始化的全局变量
BSS 段数据段上方未初始化的全局变量
向上增长动态分配的内存(malloc)
内存映射区堆和栈之间共享库、mmap
高地址向下增长局部变量、函数调用
// 内核中 mm_struct 的简化表示structmm_struct{unsignedlongcode_start,code_end;// 代码段范围unsignedlongdata_start,data_end;// 数据段范围unsignedlongheap_start,heap_end;// 堆范围unsignedlongstack_start,stack_end;// 栈范围// ... 还有页表指针等};

📐 比喻:虚拟地址空间就像一栋大楼的楼层分布图,标明了哪一层是办公室(代码段)、哪一层是仓库(数据段)、哪一层是食堂(堆)……


五、虚拟地址空间的意义

5.1 意义一:将地址从“无序”变“有序”

物理内存的分配是杂乱的,但虚拟地址空间让每个进程看到连续、整齐的地址范围,简化了程序开发。

5.2 意义二:权限保护

页表中不仅包含物理地址,还包含读写执行权限(rwx)。当 CPU 访问一个虚拟地址时,MMU(内存管理单元)会检查:

· 如果操作违反权限(比如对只读区域进行写入),则触发段错误(Segmentation Fault)。

🔒 这就是为什么字符串常量区写入会崩溃:

char*str="hello world";*str='H';// 段错误!
原因说明
字符串常量存储在只读数据段页表中该区域标记为只读
写入操作被 MMU 拦截操作系统收到异常,发送 SIGSEGV 信号
进程崩溃就是我们看到的段错误

5.3 意义三:解耦合

虚拟地址空间让进程管理和内存管理解耦合:

· 进程只关心自己的虚拟地址空间
· 操作系统负责把虚拟地址映射到物理内存
· 进程不需要知道物理内存的实际情况

🧩 好处:进程可以随便用地址,操作系统可以在后台搬家(比如页面换入换出),进程毫不知情。


六、深入理解进程的“独立性”

进程具有独立性,体现在两个方面:

独立性说明
内核数据结构独立每个进程有自己的task_structmm_struct、页表
加载进入内存的代码和数据独立通过写时拷贝,修改时物理内存分离

💡 两个进程可以拥有完全相同的虚拟地址空间布局,但映射到不同的物理内存。


七、进程挂起的深刻认识

进程挂起是指进程的某些部分(或全部)被换出到磁盘(swap 分区),以释放物理内存。

有了虚拟地址空间,挂起变得容易:

· 进程的 mm_struct 依然存在
· 页表中某些条目可以标记为“未映射”或“已换出”
· 当进程访问这些地址时,操作系统触发缺页异常,从磁盘换入

🧳 比喻:就像你出差时把行李寄存在火车站。你手上只有一张寄存凭证(虚拟地址),需要时凭凭证取回行李(物理内存)。凭证还在,行李可能不在手上。


八、再扩展一点:vm_area_struct

mm_struct 描述整个地址空间,而每个具体区域(比如堆、栈、代码段)由 vm_area_struct 来描述。

structvm_area_struct{unsignedlongvm_start;// 区域起始地址unsignedlongvm_end;// 区域结束地址unsignedlongvm_flags;// 权限标志(rwx)structvm_area_struct*next;// 链表指针};

所有的 vm_area_struct 通过链表或红黑树连接,组成了完整的地址空间布局。

📚 比喻:mm_struct 是一本书的目录,vm_area_struct 是每个章节的详细信息。

下图展示了他们与虚拟地址空间的关系


九、澄清几个问题

Q1:可以不加载代码和数据吗?

可以。 一个进程创建后,可以先只有:

· task_struct(进程控制块)
· mm_struct(地址空间描述)
· 页表

代码和数据可以按需加载(比如执行到某个函数时才把对应的代码页从磁盘读入)。

Q2:如何深刻理解写时拷贝?

写时拷贝的核心目的:

目的说明
减少创建时间fork 时只复制页表,不复制物理内存
减少内存浪费父子进程共享物理内存,只有修改时才拷贝

🚀 写时拷贝是操作系统的一种惰性优化:不到万不得已,绝不拷贝。


十、总结速查表

知识点核心内容
虚拟地址空间每个进程认为自己独占一整块内存
页表虚拟地址 → 物理地址的映射表
写时拷贝修改共享内存时,才真正拷贝物理页
mm_struct描述虚拟地址空间的数据结构
vm_area_struct描述地址空间中一个区域的数据结构
虚拟地址空间意义有序化、权限保护、解耦合
段错误本质页表权限拦截非法访问
进程独立性内核数据结构独立 + 代码数据独立
进程挂起部分内存换出到磁盘,通过缺页异常换入
写时拷贝优点减少 fork 时间,减少内存浪费

最后

虚拟地址空间是现代操作系统的基石。理解它,你就明白了:

· 为什么 fork 这么快(写时拷贝)
· 为什么字符串常量不能写(页表权限)
· 为什么两个进程的同一地址值不同(独立映射)
· 什么是“进程挂起”(换出换入)

动手试试:写一个程序,打印父子进程中同一个全局变量的地址和值,观察写时拷贝的效果。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/21 8:47:12

德州本地数字化学习工具测评:一套内部英语学习体系的落地应用

当前青少年英语学习数字化工具层出不穷,但多数产品缺少线下教学验证,内容零散不成体系。德州启飞背单词线下实体门店推出的内部专属学习体系,经过多年线下教学打磨,原本仅服务内部学员,如今对外开放,具备很…

作者头像 李华
网站建设 2026/5/21 8:46:12

从几何旋转到矩阵求逆:直观理解Givens旋转在QR分解中的作用

几何舞蹈:用Givens旋转拆解矩阵的视觉指南 想象你手中有一块复杂的拼图,每个碎片都与其他部分紧密相连。线性代数中的矩阵就像这样的拼图,而Givens旋转则是一种优雅的"旋转手法",能让我们逐步解开这个拼图。本文将带你用…

作者头像 李华