【知识讲解】 Linux虚拟地址空间认识


目录

前言

[Part1. 虚拟地址空间基础](#Part1. 虚拟地址空间基础)

[Part2. fork 与写时拷贝](#Part2. fork 与写时拷贝)

[Part2.1. fork子进程内部过程](#Part2.1. fork子进程内部过程)

[Part2.2. 写时拷贝](#Part2.2. 写时拷贝)

[Part2.3. 进程修改数据过程](#Part2.3. 进程修改数据过程)

[Part3. 缺页中断](#Part3. 缺页中断)

[Part4. 堆管理与malloc底层](#Part4. 堆管理与malloc底层)

[Part5. 虚拟地址的意义](#Part5. 虚拟地址的意义)

[Part6. 整体总结](#Part6. 整体总结)

[Part7. 结语](#Part7. 结语)


前言

在Linux操作系统中,认识虚拟地址空间是认识Linux内存管理非常重要的一部分,接下来来跟随小编的视角来看看吧。


let's go!!!!!!!!


Part1. 虚拟地址空间基础

一个进程对应一份虚拟地址空间。


• 32位机器:虚拟地址总空间 2^{32},大小4GB。

◦ 用户空间:0~3G;内核空间:3G~4G。

◦ 注意:内核空间,本质也是拿用户空间的虚拟地址去访问。

• 64位机器:拥有巨大的虚拟地址范围。


对于一个变量:

1. 变量拥有物理地址;同时,在所属进程的虚拟地址空间内,拥有虚拟地址。

2. 每个进程维护一张页表:虚拟地址 ↔ 物理地址,一一映射。

3. 小端机器取变量地址:取4字节中最小的地址;再结合类型做偏移,完成访问。


虚拟地址空间的内核数据结构

mm_struct 用来描述整个进程的虚拟地址空间。

内部包含若干个 vm_area_struct(VMA,虚拟内存区域),每一个代表一块区域:代码段、数据段、堆、栈。

每个VMA记录:start、end,代表该区域虚拟地址的起止;还有权限、偏移等属性。

虚拟地址空间是连续的;但是对应的物理内存可以是不连续。


Part2. fork 与写时拷贝

Part2.1. fork子进程内部过程

1. 调用fork(),分配内核数据结构,给子进程复制:task_struct、页表、虚拟地址空间。

2. 父进程的数据结构内容拷贝给子进程。

3. 将子进程加入运行队列。

4. fork返回,父子进程分别继续执行。

进程具备独立性:进程内部执行系统调用,都是操作自己这份虚拟内存。


Part2.2. 写时拷贝

fork刚创建子进程的时候:

1. 父子页表指向同一份物理内存,代码段、数据段共享物理页。

2. 但是把这些页的权限设置为只读。

3. 父子此时虚拟地址完全一样,映射到相同物理内存。


Part2.3. 进程修改数据过程

• CPU发现要写的页是只读,触发缺页异常。

• OS识别:这是写时拷贝场景,不是真的权限错误。

• OS分配一份新的物理内存,把原来页的内容复制过去。

• 修改当前进程的页表映射,让当前进程虚拟地址映射到新物理页;另一个进程依旧指向老物理页。

• 恢复页权限为可写,异常处理完毕,程序继续运行。

只有发生写操作,才真正分配物理内存;读操作依旧共享,不会拷贝。

fork 会返回两个id:父进程返回子进程pid,子进程返回0。本质是两个进程各自的页表,同一个虚拟地址读到不同返回值。


Part3. 缺页中断

虚拟地址已经分配,但还没有绑定物理内存,访问时触发缺页中断。


场景举例:我们程序有2G代码,虚拟地址会开辟2G虚拟空间,但是物理内存只有4G。不会一次性把全部代码加载进物理内存。

• 访问还没有映射物理内存的虚拟地址,触发缺页异常。

• 操作系统分配物理页,建立页表映射,把磁盘上对应的数据读到物理内存;异常处理完成,程序重新执行这条指令。


缺页的两种情况

1. 合法缺页:虚拟地址属于某个VMA(vm_area_struct),只是还没有分配物理页,正常分配内存即可。

2. 非法访问:访问的虚拟地址不在任何VMA之内,属于野指针,程序报段错误。


进程和内存解耦:进程的代码、数据,是基于虚拟地址。我们可以不释放虚拟地址,仅仅修改页表映射,解除和物理内存的绑定。不会影响进程运行。


进程退出

进程退出时:根据页表,把物理内存的数据写回磁盘;释放物理内存。


如果有虚拟内存,不需要把全部数据写回磁盘;只需要释放物理内存,虚拟地址本身依旧存在。


Part4. 堆管理与malloc底层

堆由vm_area_struct管理。


malloc(100)完整流程:

1. 在堆区划分虚拟地址,此时还没有物理内存。

2. 用户访问这块内存,触发缺页异常。

3. 操作系统分配物理内存,建立映射。

4. 如果堆空间不足,向OS申请更多虚拟地址。


free不会把虚拟地址还给操作系统。只是标记这块堆空间为空闲,交由malloc内部管理。堆过大才会触发堆回缩,把部分虚拟地址还给OS。


Part5. 虚拟地址的意义

1. 地址隔离保护:每个进程拥有独立虚拟地址空间,进程之间互不干扰。

2. 内存管理:虚拟地址连续,物理内存碎片化也没关系;OS可以把不常用内存置换到磁盘。

3. 权限管控:页表中设置页权限,实现只读、可读可写。访问违反权限直接触发异常。

4. 延迟分配物理内存:只有真正访问的时候,才分配物理内存。fork写时拷贝也是基于这个思想,节省内存。


Part6. 整体总结

1. 虚拟地址空间:逻辑上连续;物理内存可以离散。

2. 页表:完成虚拟地址→物理地址的翻译,同时记录页权限。

3. fork:初期父子共享物理页,标记只读;写时拷贝,发生写操作才复制物理页。

4. 缺页中断:虚拟地址已分配,无物理内存,访问触发异常;OS分配物理内存,加载数据。

5. malloc:先分配虚拟地址,真正访问才分配物理内存;free只做堆内部标记,不一定释放虚拟地址给操作系统。

6. VMA(vm_area_struct):管理各个段(代码段、数据段、堆、栈)的虚拟地址范围与权限。


Part7. 结语

这篇文章我们认识并知道了Linux虚拟地址空间,接下来,小编还会带来更多Linux相关的知识,敬请期待~
最后,祝大家可以:春风得意马蹄疾,一日看尽长安花!

最后的最后,要是觉得本文还可以的话,可以点点赞,关注小编一波,谢谢大家!~

相关推荐
新时代牛马3 小时前
Linux 驱动中断与定时完整篇:从 request_threaded_irq 到hrtimer 选型与排障
linux·运维·服务器
分支预测失败5 小时前
RISC-V 核间中断 IPI 实战:从 MSIP 寄存器到 IMSIC 消息投递
linux·后端
GeW6 小时前
RHCE考试避坑指南"90%考生容易忽略的细节
linux
键盘会跳舞7 小时前
【C++多线程】死锁诊断工具实战:从 Windows 到 Linux 的全链路排查
linux·c++·windows·死锁
拂拉氏8 小时前
【知识讲解】 Linux环境变量的认识与使用
linux·环境变量
zhangrelay8 小时前
答疑-是否软件源问题都必须更换为国内呢-
linux·笔记·学习·ubuntu·ros2
zhangrelay8 小时前
《ROS 机器人程序设计》课程教学大纲-2026- kinetic-lyrical
linux·笔记·学习·ubuntu·机器人
KFCgrandpahhh8 小时前
rk3576点灯
linux·驱动开发
拂拉氏8 小时前
【知识讲解】 Linux进程认识及深度理解
linux·进程