TLB 软件管理会有两种 TLB 失效问题,当一个页访问在内存中而不在 TLB 中时,将产生 软失效(soft miss),那么此时要做的就是把页表更新到 TLB 中(我们上面探讨的过程),而不会产生磁盘 I/O,处理仅仅需要一些机器指令在几纳秒的时间内完成 。然而,当页本身不在内存中时,将会产生硬失效(hard miss),那么此时就需要从磁盘中进行页表提取,硬失效的处理时间通常是软失效的百万倍 。在页表结构中查找映射的过程称为 页表遍历(page table walk) 。

文章插图
上面的这两种情况都是理想情况下出现的现象,但是在实际应用过程中情况会更加复杂,未命中的情况可能既不是硬失效又不是软失效 。一些未命中可能更软或更硬(偷笑) 。比如,如果页表遍历的过程中没有找到所需要的页,那么此时会出现三种情况:
- 所需的页面就在内存中,但是却没有记录在进程的页表中,这种情况可能是由其他进程从磁盘掉入内存,这种情况只需要把页正确映射就可以了,而不需要在从硬盘调入,这是一种软失效,称为 次要缺页错误(minor page fault) 。
- 基于上述情况,如果需要从硬盘直接调入页面,这就是严重缺页错误(major page falut) 。
- 还有一种情况是,程序可能访问了一个非法地址,根本无需向 TLB 中增加映射 。此时,操作系统会报告一个 段错误(segmentation fault) 来终止程序 。只有第三种缺页属于程序错误,其他缺页情况都会被硬件或操作系统以降低程序性能为代价来修复
多级页表第一种方案是使用多级页表(multi),下面是一个例子

文章插图
32 位的虚拟地址被划分为 10 位的 PT1 域,10 位的 PT2 域,还有 12 位的 Offset 域 。因为偏移量是 12 位,所以页面大小是 4KB,公有 2^20 次方个页面 。
引入多级页表的原因是避免把全部页表一直保存在内存中 。不需要的页表就不应该保留 。
多级页表是一种分页方案,它由两个或多个层次的分页表组成,也称为分层分页 。级别1(level 1)页面表的条目是指向级别 2(level 2) 页面表的指针,级别2页面表的条目是指向级别 3(level 3) 页面表的指针,依此类推 。最后一级页表存储的是实际的信息 。
下面是一个二级页表的工作过程

文章插图
在最左边是顶级页表,它有 1024 个表项,对应于 10 位的 PT1 域 。当一个虚拟地址被送到 MMU 时,MMU 首先提取 PT1 域并把该值作为访问顶级页表的索引 。因为整个 4 GB (即 32 位)虚拟地址已经按 4 KB 大小分块,所以顶级页表中的 1024 个表项的每一个都表示 4M 的块地址范围 。
由索引顶级页表得到的表项中含有二级页表的地址或页框号 。顶级页表的表项 0 指向程序正文的页表,表项 1 指向含有数据的页表,表项 1023 指向堆栈的页表,其他的项(用阴影表示)表示没有使用 。现在把 PT2 域作为访问选定的二级页表的索引,以便找到虚拟页面的对应页框号 。
倒排页表针对分页层级结构中不断增加的替代方法是使用 倒排页表(inverted page tables) 。采用这种解决方案的有 PowerPC、UltraSPARC 和 Itanium 。在这种设计中,实际内存中的每个页框对应一个表项,而不是每个虚拟页面对应一个表项 。
虽然倒排页表节省了大量的空间,但是它也有自己的缺陷:那就是从虚拟地址到物理地址的转换会变得很困难 。当进程 n 访问虚拟页面 p 时,硬件不能再通过把 p 当作指向页表的一个索引来查找物理页 。而是必须搜索整个倒排表来查找某个表项 。另外,搜索必须对每一个内存访问操作都执行一次,而不是在发生缺页中断时执行 。
解决这一问题的方式时使用 TLB 。当发生 TLB 失效时,需要用软件搜索整个倒排页表 。一个可行的方式是建立一个散列表,用虚拟地址来散列 。当前所有内存中的具有相同散列值的虚拟页面被链接在一起 。如下图所示
推荐阅读
- 图解Java内存区域
- 分享几款Linux 下C/C++程序内存泄漏检查工具
- 建议收藏 全网最全的SQL语句
- 安卓平板|vivo发布OriginOS HD大屏操作系统:手机、平板、PC无缝协同
- 白茶萎凋,白茶萎凋适度特征
- centos操作系统上实现网卡端口绑定
- 微信太“吃”内存了!教你怎样快速清理微信垃圾,释放手机内存?
- 在常用Linux操作系统中安装VMware Tools
- 聊聊 Linux 的内存统计
- 一加|12GB内存!一加首款天玑8100新机现身GeekBench:或为一加Ace
