虚拟内存技术
(这是一个MIT同学整理的6.004 Computation Structure的课程的笔记,内容清晰易懂,看一遍可以简单了解计算机组成的基本内容,一共55页,计划全部译成中文。转载请注明出处。)
(笔记原文: https://app.box.com/s/hj73i5cnek38kpy9yw22)
本地化和数据块的大小(Locality and Data Block Size)
如果你得到了位置A的存储信息,你很可能很快还会需要得到A周围的存储信息。这很自然,而且在数据存取和指令存取方面都适用。
一个关于指令读取的例子:
CPU的指令通常从内存中是按序读取的(Jump和Branch操作除外)。如你得到了位置A的指令,你很可能还需要读取A+4,A+8,A+12等等位置的信息。
缓存可以通过扩大数据块来进一步利用本地化的优势。每当对A地址的数据发生了一次Cache Miss,缓存将存入一块数据(包括A在内)。
当我们决定数据块的大小时,需要做一些性能上的平衡。太大或太小都不合适。




替换策略(Replacement Polices)
全关联及路组关联缓存需要替换策略去处理Cache的数据替换问题。
有三种常见的替换策略,包括LRU(Least recently used,替换使用最少的数据),FIFO(First-in, first-out先进先出)以及Random(随机替换)。
LRU把使用的最少的数据替换掉,从本地化(Locality)的角度看,LRU很有道理。如果特定的某些数据使用的较多,就很可能还会需要使用。但是LRU资源消耗很大,在内存使用的最坏情况下表现很差。
FIFO把最早进入Cache的数据替换掉,这比LRU的资源消耗少很多,并且更加容易实现。但也会遇到最坏情况下表现很差的问题。
Random策略随机选择一个数据进行替换。不过随机数的产生比较难。这种策略对最坏情况的表现相对较好。
写入策略(Writing Polices)
当一个数据将被替换时,它可能需要被重新写入内存(当D=1,即在Cache中被修改过)。有三种常用的写入规则。
Write through - 每次CPU发出请求写入数据时,会同时在Cache和Memory中写入。这种情况下没有Dirty Bit(用于表明该数据是否被修改)。这样做的一个优点是主存的数据不会闲置太久。缺点是每次等数据写入主存,CPU都需要等很久。比如有些函数反复修改一个变量,我们只需要把变量最后的值写入内存,把中间值写入内存显得很没必要。
Write behind - 每当CPU请求写入数据,写入Cache同时写入一个Buffer,这时CPU会继续下一条指令,而Buffer负责在后台把数据写入内存。Write behind策略也没有Dirty Bit。这种策略比Write through要好,但还是会有不必要的数据被Buffer写入内存。
Write back - 每当CPU请求写数据时,缓存会把这个数据表示为被修改(Dirty Bit = 1)。当下一次发生Cache Miss,并且该数据被替换时,如果Dirty Bit是1,就把数据写入内存,否则直接被覆盖。Write back策略是最好的,因为对内存的写入操作只有必要时才会进行。不过,wirte back策略消耗了一些存储空间用来存放Dirty Bit。
虚拟内存(Virtual Memory)
CPU中运行的程序通常使用虚拟内存而非物理内存。虚拟内存会被MMU(Memory management unit)转换成物理内存。
物理内存和虚拟内存都被分成很多区块,这些区块叫做“页”(Page)。物理内存的区块有Physical Page Number(PPN),虚拟内存的区块有Virtual Page Number(VPN)。
被写入MMU的虚拟内存地址包含VPN和page offset。MMU会找到VPN对应的PPN,MMU不会改变page offset的值。MMU的输出是一个物理内存的地址,这个地址又PPN和offset组成。PPN指向物理内存中的一个页,offset确定页中的哪个数据。

使用虚拟内存有一些直接使用物理内存没有的优点。
虚拟内存把软件和硬件分开,这样就允许软件编写时无需受到物理内存的限制,甚至允许使用一个比物理内存更大的虚拟内存,也使得分布式计算得以实现。
虚拟内存允许不同的软件之间完全独立,并且允许操作系统本身和软件分开。这就允许程序和它们的数据可以被操作系统重新安排在物理内存中 ,而且这个过程对与程序是透明的(这里我也没有完全理解)。
线性页表(Linear Page Table)
一个页表是一组在物理内存中的PPN。一个虚拟内存地址的VPN会选择一个PTE(page table entry),在这个PTE找到PPN对应的Page,再在Page中找到offset对应的物理内存地址。
一个PTE包含可选的Status Bits(比如dirty、resident、read-only、supervisor等)以及PPN。
这里谈一下Resident:这一位表示page是否在内存中,1表示在内存中,0表示没有被分配过或者在硬盘中。

分层结构页映射(Hierarchical Page Map)
在一个线性页表中,我们通常会遇到这样一个情况:很多内存都是未被使用的,这样浪费了很多的内存空间。一个可行的alleviate waste的方法是使用分层结构页映射。下图就展示了一个两层的页表,这个页表中有一个的L1页表,还有好多个L2页表(个数是 2 ^ (# L1 index) ):

转译后备缓冲器(Translation Look-aside Buffer(TLB))
TLB是一个很小的缓存,通常是全关联高速缓存,它存储了VPN到PPN的映射。如果发生TLB miss,往往会极大地拖累程序运行,因为遍历所有的页表的代价很大,或者出错。
缓存-虚拟的还是物理的?(Caches - Virtual or Physicals address)
直接关联物理地址的缓存可能不会太好,如果我们的Cache在页表被遍历的同时读取内存。
和虚拟内存绑定的Cache表现可能更好一些。但这一点超过了本文的范畴,如果修读6.823可以了解更多。
MMU简介(MMU Overview)
MMU得到一个虚拟内存地址后会经过这些步骤:
1、首先检测TLB,如果hit,就把这个地址发送到内存。否则进行步骤2
2、页表遍历-如果页表在内存中(而非硬盘中),就更新TLB,并且把这个地址发送到内存。然而,如果一个页表不在内存中最终得到的PPN并不在内存中,进行步骤3
3、Page Fault - 一个页表或者得到的PPN在硬盘上,抛出错误,在程序中处理。


浙公网安备 33010602011771号