在Linux,Windows等操作系统中,为什么不直接使用物理地址(Physical Address),而要用虚拟地址(Virtual Address)【1】呢?
因为使用虚拟地址可以带来诸多好处:
在支持多进程的系统中,如果各个进程的镜像文件都使用物理地址,则在加载到同一物理内存空间的时候,可能发生冲突。
直接使用物理地址,不便于进行进程地址空间的隔离。
物理内存是有限的,在物理内存整体吃紧的时候,可以让多个进程通过分时复用的方法共享一个物理页面(某个进程需要保存的内容可以暂时swap到外部的disk/flash),这有点类似于多线程分时复用共享CPU的方式。
既然使用虚拟地址,就涉及到将虚拟地址转换为物理地址的过程,这需要MMU(Memory Management Unit)和页表(page table)的共同参与。
MMU
MMU是处理器/核(processer)中的一个硬件单元,通常每个核有一个MMU。
MMU由两部分组成,TLB(Translation Lookaside Buffer)和table walk unit。

Page Table
page table是每个进程独有的,是软件实现的,是存储在main memory(比如DDR)中的。
Address Translation
因为访问内存中的页表相对耗时,尤其是在现在普遍使用多级页表的情况下,需要多次的内存访问,为了加快访问速度,系统设计人员为page table设计了一个硬件缓存 -TLB,CPU会首先在TLB中查找。

如果在TLB中找到了含有该虚拟地址的entry(TLB hit),则可从该entry【2】中直接获取对应的物理地址,否则就不幸地TLB miss了,就得去查找当前进程的page table(这里其实可能用到paging structure caches,将在后续文章中介绍)。这个时候,组成MMU的另一个部分table walk unit就被召唤出来了,这里面的table就是page table。
如果在page table中找到了该虚拟地址对应的entry的p(present)位是1,说明该虚拟地址对应的物理页面当前驻留在内存中,也就是page table hit。找到了还没完,接下来还有两件事要做:
既然是因为在TLB里找不到才找到这儿来的,自然要更新TLB【3】
进行权限检测,包括可读/可写/可执行权限,user/supervisor模式权限等。如果没有正确的权限,将触发SIGSEGV(Segmantation Fault)
如果该虚拟地址对应的entry的p位是0,就会触发page fault,可能有这几种情况:
这个虚拟地址被分配后还从来没有被access过(比如malloc之后还没有操作分配到的空间,则不会真正分配物理内存)。触发page fault后分配物理内存,也就是demand paging,有了确定的demand了之后才分,然后将p位置1。
对应的这个物理页面的内容被换出到外部的disk/flash了,这个时候page table entry里存的是换出页面在外部swap area里暂存的位置,可以将其换回物理内存,再次建立映射,然后将p位置1。
如果这个虚拟地址在进程的page table中根本不存在,说明这个虚拟地址不在该进程的地址空间中,这时也会触发segmantation fault。
关于在TLB中具体是怎么找的,在page table中又是怎么"walk"的,请看下回分解。
注【1】:虚拟地址在intel的手册中又被称为线性地址(Linear Address)。
注【2】:entry有入口的意思,对于TLB和单级页表的一个entry,就是指向对应page的首地址(入口);对于后文介绍的多级页表的一个entry,就是指向下一级页表的首地址(入口)。
注【3】普通cache对应的是属于物理硬件的内存,CPU可以维护cache和内存的一致性。而TLB对应的是page table(可视为一种软件的数据结构),因此需要软件(操作系统)去维护TLB和page table的一致性。




