Keyboard shortcuts

Press or to navigate between chapters

Press ? to show this help

Press Esc to hide this help

地址空间

复习

  • 读者与写者:并发读取时如何协调写入与公平性
  • 死锁是怎样形成的:四个必要条件与环形等待
  • 怎样处理死锁:预防、避免、检测和恢复的取舍

TL;DR

  • 每个进程都以为自己独占一整片连续内存
  • 这个“以为”的地址范围,叫地址空间(address space)
  • 程序里用的地址是虚拟地址,不等于真实的物理地址
  • 有了地址空间,进程之间才能互不打扰,也便于统一布局

正文

  先回忆一下前面讲过的:一个程序在内存里,分成代码区、数据区、栈和堆。可这是“一个程序独霸内存”时的样子。现在系统里同时跑着几十上百个进程,它们又是怎么共用一块内存的?

一个美好的错觉

  每个进程运行时,都觉得自己拥有一整片内存:从低地址的代码开始,一直到高地址的栈,中间是自己的数据和堆,连续、干净、没人打扰。

  可现实是:物理内存只有一根,大家必须挤在一起。那个“独占一整片连续内存”的感觉,只是操作系统给每个进程制造的错觉

  这个“错觉”里的地址范围,就叫进程的地址空间(address space)。

虚拟地址与物理地址

  错觉要成立,就得区分两套地址:

  • 虚拟地址:程序里用的地址,是它自己在地址空间里的编号
  • 物理地址:内存条上真实的地址

  程序里每一条指令、每一个变量,用的都是虚拟地址。而真正落到内存条上的,是物理地址。两套地址的换算,由硬件和操作系统在背后完成——这个换算过程,后面几章会专门讲。

进程 A 的地址空间       物理内存        进程 B 的地址空间
  虚拟 0x1000  ──┐
                 ├──>  物理 0x4000
  虚拟 0x1000  ──┘

  注意上图:A 和 B 可以拥有相同的虚拟地址,却对应不同的物理地址。互不干扰,正是靠这一点。

为什么要这样做

  给每个进程一个独立的地址空间,好处很多:

  • 隔离:A 只能访问自己的地址空间,碰不到 B 的数据,也碰不到内核
  • 方便:程序不用管自己实际被装在哪、旁边还住了谁,只管按自己的布局写
  • 灵活:物理内存不够时,还能把暂时用不到的页挪到磁盘上(后面会讲)

  又是一层抽象:把“有限的、共享的物理内存”,包装成“每个进程都独占一片连续空间”。

引出的问题

  可既然程序用的是虚拟地址,那“虚拟地址到底怎么变成物理地址”?这中间要解决两件事:程序在内存里究竟被放在哪,以及怎样拦住越界访问。下一章,我们从最朴素的办法看起。

思考题

  两个进程里有相同的虚拟地址,却指向不同的物理内存。这样做,对一个“指针写错、越界访问”的程序,是好事还是坏事?

小结

知识点

  • 每个进程以为自己独占一片连续内存,这叫地址空间
  • 程序使用虚拟地址,实际访问物理地址
  • 虚拟地址与物理地址的换算由硬件和内核完成
  • 地址空间带来隔离、方便与灵活

参考资料

  1. Wikipedia(zh):地址空间:address space
  2. Wikipedia(zh):虚拟内存:虚拟内存

思考题答案(仅供参考)

  是好事。正因为每个进程有独立的地址空间,一个程序即使指针写错、越界访问,它也只能在自己那片空间里乱撞,撞不到别的进程,更撞不到内核;最坏的结果是它自己崩溃。如果没有这层隔离,越界就可能改坏别人的数据,甚至拖垮整个系统。所以地址空间不仅提供了方便,更是一道安全边界。

协议

  本作品采用知识共享署名-非商业性使用-相同方式共享 4.0 国际许可协议进行许可。

封面图

设计师 | 南国微雪