操作系统是如何让不同的应用程序能够既安全又高效地共同使用物理内存的?
现代操作系统的普遍做法是引入“虚拟内存”的机制,应用程序是面向虚拟内存编写的而不是面向物理内存。应用程序在运行的时候使用的是虚拟地址,CPU负责将虚拟地址转换为物理地址。
使用虚拟地址来访问内存
CPU负责将虚拟地址转换为物理地址,这个过程称为翻译。这个过程是由内存管理单元(MMU)来完成的。为了加速地址翻译的过程,现代CPU都引入了转址旁路缓存(Translation Lookaside Buffer, TLB)。TLB是属于MMU的内部单元。
分段与分页机制
分段机制
应用程序的虚拟地址空间由若干个大小不同的段构成,当CPU要访问某个段时,MMU会去查询段表,得到该段对应的内存区域。
具体来说,虚拟地址由两部分构成:段号和段内偏移。首先MMU通过段表基址寄存器找到段表的位置,然后根据段号找到对应的段的信息,接着取出该段,将段的起始地址加上段内偏移,得到物理地址。
分段机制下,会出现外部碎片,降低内存资源的利用率。
分页机制
分页机制是将虚拟地址空间以及物理内存都划分为连续的、等长的虚拟页。这样就可以构建页表,该机制下的虚拟地址也由两部分组成:虚拟页号和页内偏移量。分页机制避免了外部碎片的问题。
但是,要是采用一张页表的话,页表将会非常庞大。于是现代的操作系统都会采用多级页表。对于不存在对应的页的页表,将不会被创建。也就是说,每张页表都是一个数组,但是多级页表的机制可以使得大部分的页表都不会被创建,只会创建那些存在对应页面的页表。这样子就可以解决页表空间占用的问题。
转址旁路缓存
TLB可以看成存储着键值对的哈希表。并且,TLB也采用和CPU缓存类似的分层结构。如图:
在AArch64和x86-64的体系结构下,TLB在地址翻译过程中是由MMU进行管理的。硬件规定了页表的基地址的位置以及页表的内部结构,操作系统秩序按照硬件的规范来构造和配置页表。在一些体系结构设计中,允许软件在地址翻译过程中对TLB进行管理。
TLB刷新
TLB刷新是为了保证TLB中的内容与当前页表中的一致。
为了减少操作系统在切换应用程序的过程中刷新TLB,以AArch64为例,它提供了ASID(Address Space IDentifier)(x86-64中称为PCID)。操作系统可以为不同的应用程序分配不同的ASID作为其身份标签。
ASID最多有16位(位数由TCR_EL1寄存器中的信息决定)
参考资料 《现代操作系统:原理与实现》陈海波 夏虞斌等著
转载请注明来源:https://www.longjin666.top/?p=1168