进程隔离是操作系统内核对于资源管理和安全增强的特性,其最终的目的是对于操作系统内核能够更好的控制程序对资源的申请和使用,并且控制此程序可访问资源的范围并限定此程序异常之后能够影响的范围。
进程隔离对硬件有一些基本的要求,其中最主要的硬件是MMU (Memory Management Unit 内存管理单元),MMU的作用简单用一句话概括就是将线性地址(虚拟地址)翻译为物理地址
为什么需要线性地址(虚拟地址) 到 物理地址的翻译
如果没有线性地址的概念只有物理地址会出现的问题:
- 整个操作系统能够访问的地址空间和实际插入的物理内存大小相关。
- 每个进程能够访问的地址空间是从物理内存空间上的一部分。
- 编译生成的程序需要事先知道运行在物理地址空间的范围,才能够生成相应的执行代码。
对于通用的操作系统来说,其能访问的内存空间是根据地址线的范围来决定的,例如32位系统就是2^32, 而对于64位操作系统是2^48 不会因为实际插入的物理内存大小的变化而变化, 而同样的为操作系统编译生成的可执行程序需要具有通用性,而不能针对不同的硬件都重新生成可执行程序来适配不同的物理内存大小和范围。
引入了线性地址到物理地址的翻译就能够解决以上的问题
Linux内核的地址空间为 3-->4GB的线性地址高位空间(同一个内核的地址空间映射在每个进程的3-->4GB的内存范围内), 而对于0 -- > 3GB来说为每个进程自己的用户态地址空间范围。 所以每个不同的应用程序在运行时其进程的0 -- > 3GB为它们的可访问地址范围,虽然它们的代码逻辑完全不同,但是内存的可访问范围却完全相同。
分页内存访问的操作系统如何做到进程的线性地址空间隔离
操作系统内核上电之后会初始化MMU并将自己映射到3-- > 4GB的线性地址空间, 而当我们通过系统调用如fork创建进程时,其会在进程描述结构体内集成内存虚拟地址空间的结构体,其内容包含的是当前进程的地址空间页表,当操作系统进行任务切换时会改写CPU的页表基地址寄存器为当前被运行进程的页表基地址,从而达成切换地址空间范围到相应的进程内存范围的目的。