下面是《【寻找Linux的奥秘】第七章:虚拟地址空间》的详细内容解读与结构化整理,适用于希望深入理解 Linux 虚拟内存管理机制的开发者与系统学习者。
📚 目录
- 什么是虚拟地址空间?
- 用户态与内核态的地址划分
- 虚拟内存区域(VMA)介绍
- Linux 进程地址空间布局
- 页表与地址映射机制
- 动态内存分配与映射方式
- 共享内存与匿名映射
- 虚拟地址空间与安全隔离
- Linux 中虚拟地址空间查看命令
- 总结与学习建议
1️⃣ 什么是虚拟地址空间?
虚拟地址空间是操作系统为每个进程提供的“独立”地址空间。每个进程都认为自己独享从 0 开始的地址空间,而实际上这些地址会映射到物理内存或交换空间。
本质:
- 虚拟地址 ≠ 物理地址
- 通过硬件(MMU)+ 软件(内核)协作完成映射
2️⃣ 用户态与内核态的地址划分
在 32 位 Linux 系统中,虚拟地址空间通常被划分为两部分:
区域 | 地址范围 | 权限 | 描述 |
---|---|---|---|
用户空间 | 0x00000000 ~ 0xbfffffff | 用户可访问 | 每个进程独立 |
内核空间 | 0xc0000000 ~ 0xffffffff | 仅内核访问 | 所有进程共享同一内核映射 |
在 64 位系统中,用户空间可扩展至 TB 级,具体取决于平台和内核编译选项。
3️⃣ 虚拟内存区域(VMA)介绍
VMA(Virtual Memory Area) 是 Linux 用来描述进程地址空间中一个连续区域的数据结构。
每个进程都维护一个 mm_struct
结构体,内部通过红黑树或链表管理多个 VMA。
每个 VMA 包含内容:
- 起始地址与结束地址
- 访问权限(读、写、执行)
- 映射的文件(如 ELF、共享库)
- 匿名页(malloc 或栈)
4️⃣ Linux 进程地址空间布局
一个典型的进程虚拟地址空间由以下几个区域组成:
低地址
|
| text(代码段)
| data(已初始化数据段)
| bss(未初始化数据段)
| heap(堆,向上增长)
| mmap 区域(共享库、文件映射)
| stack(栈,向下增长)
| 内核空间
高地址
5️⃣ 页表与地址映射机制
虚拟地址需通过页表转换为物理地址。Linux 使用分级页表,通常包括以下几级:
- PGD(Page Global Directory)
- PUD(Page Upper Directory)
- PMD(Page Middle Directory)
- PTE(Page Table Entry)
每次内存访问都通过这些表进行查找并转换。
6️⃣ 动态内存分配与映射方式
malloc / calloc:
- 调用
brk()
或mmap()
系统调用 - 在虚拟地址空间的 heap 区域或匿名映射区域分配
文件映射(mmap):
- 使用
mmap()
映射文件或设备 - 可选择是否共享、是否匿名、读写权限等
7️⃣ 共享内存与匿名映射
mmap()
可实现内存共享(如线程间共享内存)- 匿名映射(
MAP_ANONYMOUS
)用于无文件 backing 的内存,如线程栈、临时缓冲区
多个进程或线程可通过 mmap + MAP_SHARED
来映射同一段物理内存区域。
8️⃣ 虚拟地址空间与安全隔离
虚拟地址空间为每个进程提供“沙箱”式运行环境:
- 防止进程互相访问彼此内存
- 内核空间与用户空间分离,避免用户代码直接操作内核内存
- 若访问非法地址,触发
segfault
(段错误)
9️⃣ Linux 中虚拟地址空间查看命令
查看进程的地址空间布局:
cat /proc/<pid>/maps
示例输出:
00400000-0040b000 r-xp 00000000 fd:00 123456 /usr/bin/ls
0060a000-0060b000 r--p 0000a000 fd:00 123456 /usr/bin/ls
...
7fffe12b000-7fffe14c000 rw-p 00000000 00:00 0 [stack]
每一行表示一个 VMA 区段,包括:
- 起始和结束地址
- 权限(rwx)
- 映射文件或 [heap]/[stack]/[vdso]
查看某地址所属页表项:
sudo cat /proc/<pid>/pagemap
或使用专用工具:
pmap <pid>
🔟 总结与学习建议
- 虚拟地址空间是进程隔离的关键保障
- 每个进程拥有独立 VMA 结构描述其地址区域
mmap()
是内存映射与文件共享的强大工具- 掌握
/proc/<pid>/maps
输出有助于调试段错误 - 进一步建议阅读 Linux 源码中的
mm
子系统代码,如do_mmap
,vm_area_struct
等
发表回复