前言

前不久、我们详细分析了TLB基本原理,本节我们通过一个简单的示例再次叙述TLB的算法和原理,希望借此示例能加深我们对TLB(又称之为快表,深入理解计算机系统(第三版)又称之为翻译后备缓冲区)的理解。

使用分页作为支持虚拟内存的核心机制可能会导致高性能开销,通过将地址空间划分成固定大小的小单元(即页面),分页需要映射大量信息,由于该映射信息通常存储在物理内存中,因此在逻辑上分页需要针对程序生成的每个虚拟地址进行额外的内存查找,在每条指令获取或显式加载或存储之前进入内存获取翻译信息的速度会非常慢。因此,我们的问题演变为:如何对逻辑地址进行高速翻译?我们如何加快地址转换的速度从而避免在分页时需要额外的内存引用?硬件支持是必要的吗?哪些操作需要操作系统参与?

TLB(快表,翻译后备缓冲区)原理和练习

当我们想加快查找速度时,通常需要借助于操作系统通常来完成,那就是来自操作系统的老朋友:硬件。为了加快地址翻译速度,我们将添加一个称为翻译后备缓冲区(TLB),TLB是芯片的内存管理单元(MMU)的一部分,因此,TLB是虚拟地址到物理地址翻译的硬件缓存。在每次引用虚拟内存时,硬件首先检查TLB,以查看是否已保留了所需的翻译(PTE),否则,硬件将检查TLB。如此这样将执行快速翻译而不必每次都去查阅页表(包含所有翻译),因每次进行内存引用必将对对性能的巨大影响,所以从另外一个角度讲,实际上TLB使虚拟内存成为可能。逻辑地址并计算出VPN、如何查找TLB、TLB缺失后如何处理等等通过图解方式来进行详细叙述,这里我们通过伪代码方式来进一步讲解TLB整个大概原理过程若有错误之处,还请批评指正,存有疑惑之处,还请先看操作系统专辑中对此更容易理解的叙述

 VPN = (VirtualAddress & VPN_MASK) >> SHIFT;
(Success, TlbEntry) = TLB_Lookup(VPN);
if (Success == true)
{
if (CanAccess(TlbEntry.ProtectBits) == true)
{
Offset = VirtualAddress & OFFSET_MASK;
PhysAddr = (TlbEntry.PFN << SHIFT) | Offset;
Register = AccessMemory(PhysAddr);
}
else
{
RaiseException(PROTECTION_FAULT);
}
}
else
{
PTEAddr = PTBR + (VPN * sizeof(PTE));
PTE = AccessMemory(PTEAddr);
if (PTE.Valid == False)
RaiseException(SEGMENTATION_FAULT);
else if (CanAccess(PTE.ProtectBits) == false)
RaiseException(PROTECTION_FAULT);
else
TLB_Insert(VPN, PTE.PFN, PTE.ProtectBits);
RetryInstruction();
}

从逻辑地址提取出VPN(第1行),调用TLB_Lookup方法查找TLB中是否存持有VPN的翻译(第2行),获取到TLB是否命中的标识(Success)和TLB条目。若TLB命中(第3行),获取TLB条目中的保护位并调用CanAccess方法判断是否可访问(第5行),若可访问,从逻辑地址中提取出偏移量(第7行)。通过TLB条目中的物理页帧号即PFN、页偏移量以及基于页起始位置偏移计算出物理地址(第8行),传递物理地址并调用访问主存方法AccessMemory,使得寄存器指向主存地址空间(第9行)若TLB缺失(第16行),通过VPN和页表基寄存器计算PTE地址(第18行),传递PTE地址调用访问主存方法AccessMemory,这里是访问主存页表从而获取PTE,很显然,访问主存页表将导致额外的内存引用,操作成本很高(第19行),若PTE有效位为无效(第20行),则引发错误(第21行),同理若不可访问则引发保护位错误,这个时候将交由操作系统来进行缺页处理进行页面置换。否则调用TLB_Insert方法,将VPN和PTE中的PFN和保护位插入到TLB条目(第25行),一旦更新了TLB条目,那么硬件将重试缺页指令,如此将加速翻译,快速处理内存引用(第26行)

为了更清楚说明TLB的作用,我们通过一个简单的示例来跟踪虚拟地址翻译,最后看看TLB如何改善其性能。在此示例中,假设内存中有10个4字节整数的数组,从虚拟地址100开始。进一步假设我们有一个小的8位虚拟地址空间,具有16字节页面;因此,虚拟地址分为4位VPN(有16个虚拟页面)和4位偏移(即每页面有16个字节)。如下求数组元素之和

int sum = ;

var array = new[] { , , , , , , , , ,  };

for (int i = ; i < ; i++)
{
sum += array[i];
}

上述数组中的10个元素在页表中的存放大概如下图所示,第1个元素位于(VPN = 6,偏移量 = 4),所以在第6页只能容纳3个4个字节整数元素,紧接着其他元素则分别放在第7和第8页。

为了简单起见,我们假设循环生成的唯一内存访问就是对数组的访问,忽略变量i和sum以及指令本身。当访问第一个数组元素(a[0])时,CPU将加载100的虚拟地址,硬件从地址中提取VPN(VPN = 06),并使用该地址检查TLB的有效转换,假设这是程序第一次访问数组,则结果将是引起TLB缺失。下一步开始访问元素a[1],好消息是:TLB命中,因为数组的第二个元素紧挨着第一个元素,所以它位于同一页上,因为在访问数组的第1个元素时已经访问了此页面,所以翻译已经加载到了TLB中。当访问元素a[3]时,此时又会引起页缺失,但接下来的a[4]..a[6]都将命中,因为它们和a[3]都在内存中同一页上。我们总结一下对数组的10次访问期间的TLB活动:未命中,命中,命中,未命中,命中,命中,命中,未命中,命中,命中。因此,我们的TLB命中率(即命中数除以访问总数)为70%

虽然这不是太高(实际上,我们希望命中率接近100%),但它不是零,这可能令人惊讶。即使这是程序第1次访问该数组时,由于空间局部性,TLB还是会提高性能。数组的元素紧密地包装在页面中(即它们在空间上彼此靠近),因此只有第1次访问页面上的元素才会产生TLB未命中。其实这也我们联想到了为何要进行缓存预热,因为第1次访问会导致缓存强制缺失。如果页面大小只是原来的2倍(32字节,而非16字节),则数组访问将遭受更少的丢失。由于典型的页面大小是4KB,因此这些类型的密集,基于数组的访问可凸显出出色的TLB性能,每页访问仅遇到一次未命中。

关于TLB性能的最后一点:如果程序在此循环完成后不久再次访问了数组,则假设我们有足够大的TLB来缓存所需的翻译,那么我们可能会看到更好的结果:命中,命中,命中,命中,命中,命中,命中,命中,命中,命中。在这种情况下,由于时间局部性即时间上的快速重新引用,TLB命中率会很高,像任何高速缓存一样,TLB依赖于时间和空间局部性而获得成功,程序具备这两个属性,往往大多时候,此二者不可同时兼得。

总结

相信之前和通过本节专述TLB原理,同时结合一个简单的示例详细的讲解,能够让大家更加明白TLB的实际作用,下一节我们进入关于操作系统内存管理最后一小节内容作为总结,然后我们开始进入程序执行、线程、进程等内容,感谢您的阅读,我们下节见。

读懂操作系统之快表(TLB)原理(七)的更多相关文章

  1. 读懂操作系统之缓存原理(cache)(三)

    前言 本节内容计划是讲解TLB与高速缓存的关系,但是在涉及高速缓的前提是我们必须要了解操作系统缓存原理,所以提前先详细了解下缓存原理,我们依然是采取循序渐进的方式来解答缓存原理,若有叙述不当之处,还请 ...

  2. 读懂操作系统之虚拟内存TLB与缓存(cache)关系篇(四)

    前言 前面我们讲到通过TLB缓存页表加快地址翻译,通过上一节缓存原理的讲解为本节做铺垫引入TLB和缓存的关系,同时我们来完整梳理下从CPU产生虚拟地址最终映射为物理地址获取数据的整个过程是怎样的,若有 ...

  3. 【Java基本功】一文读懂String及其包装类的实现原理

    String作为Java中最常用的引用类型,相对来说基本上都比较熟悉,无论在平时的编码过程中还是在笔试面试中,String都很受到青睐,然而,在使用String过程中,又有较多需要注意的细节之处. S ...

  4. 读懂操作系统(x86)之堆栈帧(过程调用)

    前言 为进行基础回炉,接下来一段时间我将持续更新汇编和操作系统相关知识,希望通过屏蔽底层细节能让大家明白每节所阐述内容.当我们写下如下C代码时背后究竟发生了什么呢? #include <stdi ...

  5. 读懂操作系统(x64)之堆栈帧(过程调用)

    前言 上一节内容我们对在32位操作系统下堆栈帧进行了详细的分析,本节我们继续来看看在64位操作系统下对于过程调用在处理机制上是否会有所不同呢? 堆栈帧 我们给出如下示例代码方便对照汇编代码看,和上一节 ...

  6. 一篇文章读懂HTTPS及其背后的加密原理

    HTTPS(全称: Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.本文,就来深入介绍下其原理. 1 ...

  7. 一文读懂机器学习大杀器XGBoost原理

    http://blog.itpub.net/31542119/viewspace-2199549/ XGBoost是boosting算法的其中一种.Boosting算法的思想是将许多弱分类器集成在一起 ...

  8. 《一篇文章读懂HTTPS及其背后的加密原理》阅读笔记

    HTTPS(Hypertext Transfer Protocol Secure,超文本传输安全协议),是以安全为目标的HTTP通道,简单讲是HTTP的安全版.这篇文章深入介绍了它的原理. 当我们适用 ...

  9. 一文读懂 SuperEdge 边缘容器架构与原理

    前言 superedge是腾讯推出的Kubernetes-native边缘计算管理框架.相比openyurt以及kubeedge,superedge除了具备Kubernetes零侵入以及边缘自治特性, ...

随机推荐

  1. String类基础知识

    1.String类的构造方法 (1)String(String original)  //把字符串数据封装成字符串对象 (2)String(char[] c)   //把字符数组的数据封装成字符串对象 ...

  2. 【思考】URI和URL的区别?以及URL的结构

    URI = Universal Resource Identifier URL = Universal Resource Locator 在学习中,我们难免会遇到 URI 和 URL,有时候都傻傻分不 ...

  3. docker创建tomcat容器

    配置阿里云镜像地址:先在阿里云搜索:容器镜像服务  --> 最下面找到 容器加速服务  docker配置  etc目录下 创建docker文件夹 mkdir --->docker  --- ...

  4. script写在head与写在body中的区别

    咱先说将Javascript写在head里面的情况吧,如果你要在这里面去操控DOM元素,是会报错的,因为浏览器是先执行head标签里面的内容,在执行时你的DOM元素还没有生成.(使用了windows. ...

  5. egret canvas的style

    <canvas width="1920" height="1080" style=" cursor:auto;//鼠标样式 positon:ob ...

  6. Idea+springboot入坑之路

    环境准备 IDEA 社区版: 2019.3 jdk: 1.8.0_241 tomcat: 7.0.99 maven: 3.6.3 spring-boot:2.2.5.RELEASE 插件 spring ...

  7. C#由转换二进制所引起的思考,了解下?

    前言 最近遇到很有意思转换二进制的问题,有部分童鞋俨然已了解,可能也有一部分童鞋没碰到过也就不知情,这里我们来深入学习下转换二进制所带来的问题. 二进制转换问题 假设现在我们有一个int类型的数据,它 ...

  8. js的几个小问题

    1.存一个有效期为7天的cookie,key = nickname, val = Ace 代码: function setCookie(key,val,expires){ let now=new Da ...

  9. css实现内容渐变隐藏效果,手机网页版知乎内容隐藏效果的实现

    看到一个需求,如下图,知乎手机网页版的一个视觉效果,对内容很长的部分有一个渐变的隐藏的效果,个人觉得这个设计还是很好的,符合手机大小的应用场景,没有一下子显示完全,可以很快的滑倒页面底部,一定程度上减 ...

  10. 详解GaussDB bufferpool缓存策略,这次彻底懂了!

    摘要:华为云GaussDB(for mysql)是华为云自主研发的最新一代云原生数据库,采用计算存储分离.日志即数据的架构设计.具备极致可靠.极致性价比.多为扩展.完全可信等诸多特性. 一 .Gaus ...