参考:CSAPP第九章虚拟内存
pleasewhy/xv6-book-2020-Chinese: MIT 6.S801 xv6 book 2020版 中文翻译
1.CPU直连内存
单片机就是这样,51 stm32之类的。

2.MMU虚拟内存管理单元
具有MMU的soc才能跑linux操作系统,因为程序运行时必须要保证内存连续性,否则程序之间那可不就乱了套了吗。没有MMU的最多只能跑简单的RTOS,RTOS的任务切换实际上也是页表(一块块被划分好的内存区域)的切换,但是复杂度低了很多很多,本质就只是汇编级别的硬跳转(上下文切换)。
MMU的工作机制本质是CPU发出虚拟内存寻址指令,MMU进行地址翻译,把找到的地址再去内存里找真实物理地址实现,最后再把内存中指定地址数据返给CPU。

3.Page tables
页表就是MMU创建的英汉大字典,MMU通过它查找VA和PA的对应关系。当然字典很厚,找的速度也相对较慢。这个问题TLB可以解决,稍后介绍。
页表在XV6中分为了三层,如果只有一层那么每个页占据的空间足有27位,这样严重浪费了内存地址。就像你的字典目录不会把每个单词都单开一行。三级基本上对应了目录的章、节、页,每部分9位,数据量从2^27下降到了 3 * 2^9。

-
VA(virtual address)虚拟内存地址访问
- 也叫VP(virtual page),总共64位,顶部EXT25位未使用,27位对应3*9三级页表,12位offset对应PA的12位offset
-
Page tables
- PTE(page table entry)是Page table的最小单元,它由PPN和flags组成,实际上是三个表,27位由前到后是L2 L1 L0对应三个表,每个表2^9 (0-511)
-
PA(physical address)物理内存地址访问
- 也叫PP(physical page)
4.虚拟内存virtual memory
虚拟内存就是磁盘空间的一部分,它是被分配的连续数组,用于内存不足时的缓存。同样的虚拟内存也拥有虚拟地址,和虚拟页表VP(块控制)这样CPU就像访问内存一样访问虚拟内存。
简单来说虚拟内存可以类比于工作台旁的多层置物架,有多少层由用户决定,但是真正的计算还是在工作台(内存中)完成。所以虚拟内存存在三种状态:
-
未分配
-
已缓存
-
未缓存
也可以看作是一个速度慢的cache。CPU旁的cache被定义为SRAM,虚拟内存系统(内存条)被定义为DRAM。速度差10倍左右。虚拟内存VM,是在磁盘分配的连续空间。
同样的我们的页表也要更新。

5.TLB(Translation Lookaside Buffer)转译后备缓冲器
大家都用过字典,查page table表是一个费力不讨好的工作,所以MMU拥有了属于自己的一级缓存cache,也就是TLB,快速存储读取数据,节约了大量的时间。可以类比是你在字典中折起来的那几个页码,TLB肯定是很小的,这是为了速度做出的妥协,找不到的时候就去页表里面找。
至此也可以把现在的cpu与内存之间的总体关系全部画出来了。

6.page fault问题
page fault如果发生有相当的概率会导致系统崩溃。缓存没有命中TLB或者Page table,称为page fault,缺页存在的整体流程及情况见图。

page fault的具体原因有5:
-
页真的不在内存
-
虚拟页被换出到磁盘 swap
-
或者从来没被加载过
-
-
访问权限错误
也会触发segfault 段错误
-
写只读页(text 段)
-
执行不可执行页(data段)
-
访问特权页(kernel地址)
-
-
页不存在(无效虚拟地址)
PTE 根本无效,非法地址 → segfault
-
访问未映射的虚拟地址
-
野指针、空指针、越界访问
-
-
copy-on-write
-
父子进程共享同一张物理页,一旦写入:触发 page fault
-
OS 复制一页新物理页,修改页表→ 这是正常、高效的 page fault,不是错误
-
-
TLB缺失
- 不算page fault,只有页表也不命中时才是page fault。
7.Linux虚拟内存系统总结
如果没有MMU,那么基于risc-v的芯片都是full descending满递减堆栈。从上到下依次是:

有了MMU之后每个进程都有了自己完全独立的虚拟内存空间,它觉得自己就是内存里面唯一运行的程序。
