CSAPP第十章——虚拟存储器 阅读笔记(未完成)

         记得在我01读大学的时候,电脑内存的标配是128 256M 之间,到如今,笔记本上的内存 1G 2G 都是常事。可见内存容量的发展是多么的快速。诚然,在拥有更多的内存的机器上运行程序,当然会快速很多,但小内存机器也一样能把程序跑起来。我记得我玩文明4的时候,用我的本本玩(756MDDR2)的内存,1分钟左右就进去了吧,后来用我大学的机器( 256M )玩,可怜花了半个小时才进去,而且不小心切换了一个页面,又要等上个半个小时,那一个痛苦啊。。。。。。不过话又说回来了,不管等了多久,好歹他还能跑起来。这都得归功于虚拟内存。接下来我们就来看看他到底是怎么回事。

一、基本概念

在很早之前(我没赶上那个时候:)),是没有多进程的概念的,一个程序在执行过程中,独占所有电脑的资源,包括内存,他也是独享的。实际的物理内存有多大,程序的空间也就只能考虑多大。好在他是一个程序自己用全部的内存,再加上那时程序也不太大,虽然麻烦,但也勉强凑合。随着后来程序越来越大,再加上多进程的出现,在根据实际内存来划分,就显得非常吃力了。所以才有了虚拟内存的概念。首先,我们先了解一下缓存的概念。

1.  缓存

CPU与外部存储设备交互数据时,由于外部存储器数据的读取往往比CPU慢很多,所以在CPU和外部设备之间,增加一个更快速的存储器,既缓存。以减少CPU的等待时间。

在知道了还缓存的概念之后,相信大家都记得intel处理器的一级缓存,二级缓存的概念吧。就是为了在CPUDRAM之间加一层更快的存储器。记得在01年,还只有一级缓存L1,好像还在128k256k左右徘徊。现在都是 1M 2M 的水平了。好了,接下来看看什么叫虚拟存储器。

 

2.  虚拟内存

如果将要运行的程序,比内存的空间还要大时,就使用一部分磁盘空间用做内存使用,把当前使用的数据调入内存,暂不使用的数据放在磁盘中。当作内存使用的这部分磁盘空间,就是虚拟出来的内存。

这样就解决了一个程序因实际物理内存而受到的限制。在此我们必须想到一下几个问题:

1>>既然程序不是按照实际的物理地址计算空间的,如何对一个可执行文件编址(虚拟地址);

2>>一个可执行文件的地址空间又是如何和实际的物理空间对应的(地址映射);

3>>我们以多大的单位让程序的空间和物理空间一一对应(页面);

4>>如何才能定位CPU所需要的数据是在内存的什么地方(页表);

5>>怎样才能知道那些数据是要使用,那些是要放入内存的(命中,缺页,替换机制);

6>>更重要的是现在计算机都是多个进程同时存在内存之中的,怎样保证各个进程之间不会相互影响(用户空间和内核空间);

 

       把上面的问题想清楚了,也就大概知道虚拟存储器是如何工作的了。所以呢,我们首先区别一下虚拟地址和物理地址的概念。

 

3.  虚拟地址和物理地址

对于每个进程,既然不需考虑实际的物理地址,那就可以为每一个进程提供一个大的、一致的、私有地址空间。在32位系统中一般为每个进程提供 4G 大小的虚拟地址空间。进程可以根据一定的结构,使用这 4G 的地址空间。程序在编译链接的过程中,也就按这 4G 的空间分配地址,既是虚拟地址。

对于物理地址,就是对应于实际存在的物理内存,为此物理空间进行编址。每一个字节即对应一个物理空间。

 

4.

  把虚拟空间中4GB的地址空间,划分为一个个大小一定的片段,我们称之为“页”。同样,在物理空间中,也做同样的划分,使虚拟地址与物理地址可以按固定大小页对应起来。在这里我们必须注意的是,物理页面是可以装载任何的一个虚拟页面的。我们可以把物理页面看成一个固定大小的盒子,而虚拟地址空间的页面是要放入盒子的东西,只要大小合适,都可以放入盒子。

 

5. 地址映射和页表

       如何将虚拟地址和物理地址一一映射?首先系统会为每一个进程保存一张或多张页表,页表就维护这虚拟地址到物理地址的对应关系。当CPU需要从内存读取数据,就把虚拟地址发给MMUMemory Management Unit),MMU通过查找页表等操作,就可以得到物理地址。

 

6. 命中、缺页、替换机制

由于物理内存的大小比进程的虚拟空间通常要小,所以当前进程并不是所有的页面都能存放在物理内存中。当CPU需要的数据所在的页面在物理内存中的情况,我们称为命中。反之,如果不再物理内存中,我们称为缺页。于是,就按照一定的替换机制,把当前在内存中的页面调离内存,把所需的页面替换如内存。因此,页面也就可以划分为三个不相交的子集:

1.未分配的:VM系统还未分配(或者创建)的页,未分配的块没有任何数据和他们相关联。因此也就不占用任何磁盘空间。

2.缓存的: 当前缓存在物理存储器中的已分配页。

3.未缓存的:没有缓存在物理存储器中的已分配页。

 

7、高速缓存和TLB

   对于现在的CPU速度而言,内存的速度还是显得不够快。为了提高CPU的使用率,于是在CPUDRAM之间,又加了级高速缓存,高速缓存容量不大,但通常比DRAM有更快的存取速度。因此能缩短CPU的等待时间。TLBTranslation Look-aside Buffer)俗称快表,目的是用来存放页表。由于页表一般存放在高速缓存,或者内存中。为了提高页表的查询速度,就把部分页表放在读取速度更快的一段buffer中,既TLB

 

 

二、虚拟存储器

大家看完了第一章的一大堆概念,是不是感觉晕头转向的啊。呵呵,不用怕,现在,我们给他一个统一的大名字——虚拟存储器(VM),我们可以把VM当成上面所有概念的集合。下面我摘抄CSAPP书中第十章的一段话“虚拟存储器是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互。他为每个进程提供了一个大的、一致的、私有地址空间。通过一个很清晰的机制,虚拟存储器提供了三个重要的能力:1. 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动的区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,他高效的利用了主存。2. 他为每个进程提供了一致的地址空间,从而简化了存储器管理。3. 它保护了每个进程的地址空间不被其他进程破坏。”

虚拟存储的概念是现代计算机系统中最重要的概念之一,用虚拟存储器作为存储器管理的工具,可以带来一下几个好处:(摘自CSAPP):

1.简化链接。

由于每个进程都是有自己独立的地址空间,也就允许每个进程为它的存储器映像使用相同的基本格式,而不管代码和数据实际存放在物理存储器的何处。所以这也就大大简化了链接器的设计,允许链接器按照虚拟地址空间生成全连接的可执行文件。

2. 简化共享

我们可以通过虚拟内存机制,将多个进程的虚拟页面映射到同一个物理页面,从而达到进程间共享。如对于库函数printfLinux如果为每个进程都维护一个printf的拷贝,将极大的浪费内存空间。因此,可以通过页面共享,使多个进程共享这部分代码的一个拷贝。

       3. 简化存储器分配

    当一个进程需要分配大块连续的空间的时候,在虚拟空间处作出分配后,由于虚拟页面可以分配在任何的物理页面中,因此不必要求物理页面是连续的。

4.简化加载

加载器不需要为某个启动进程真正的从磁盘拷贝数据到内存中。而是当某个页面第一次引用的时候,通过页面调度,把所需的页面加载入内存。

 

 

三、地址翻译

       在这节,我们着重介绍一下MMU是如何从虚拟地址转换成物理地址的,以及TLB和高速缓存的工作原理。为了简单,我们先从一级页表入手。我们先看一下虚拟地址和物理地址的格式:

   

       从上图中,我们可以看到物理地址和虚拟地址都可以分为两个部分,页号和页偏移。对于一个典型的32位的Intel体系结构,页大小一般为4k。所以低12位的页偏移可以表示整个4k的页面,高20为可以用来表示页号,所以可以用 1M 个页表号,其地址空间就可以达到 1M ×4K,一共4GB的空间。

   在不考虑高速缓存和TLB的情况下,整个过程可以分为三个部分:

1、  MMU通过页表基址寄存器(PTBR)找到页表;

2、  并且在页表中根据虚拟地址的VPN部分,找到相应的PPN(物理页号);

3、  然后在和虚拟地址的VPO部分合并,即可得到物理地址。

然而,为了更快速的得到所需的数据,我们期望减少数据获取时间。整个过程中最耗时的应该是读取内存或高速缓存的时间。我们在两个地方,要在存储设备中读取数据,一是从高速缓存中读取页表,二是从内存中读取数据。所以我们可以在这两个地方着手优化速度。对于页表的读取,我们使用TLB快表,让部分数据放在次缓存区,以减少高速缓存的读取,第二把数据放在高速缓存,以减少内存的读取。

下面我们看看如何使用TLB和高速缓存的。首先我们必须了解数据是以何种形势存放在这个存储介质之中。对于TLB和高速缓存,数据都是以n路组相连的方式存放的。所谓n路组相连,就是把数据划分为m组,每一组都有n项,也就是n路。然后对于某一组中的某一项,我们用一个标记来识别。对于一个32位的地址,我们要定位一个n路组相连的条目。就必须至少两个条件:组索引,和组标记。我们根据组索引确定组的位置,然后根据标记来查找n路中哪一条使我们所需要的数据。

在知道数据的存储方式之后,看看TLB的使用方式,当CPU将所需数据的虚拟地址交给MMU之后,MMU取虚拟地址的VPN部分,将VPN划分为TLBTTLBI两部分,根据组索引TLBI确定页表条目所在的组,然后在根据标记TLBT来确定页表条目,因此就可以从页表条目中读取物理页号了。把在快表得到的物理页号PPN和虚拟地址的页偏移VPO结合,就生成了物理地址。当然了,也会发生在快表中无法找到相关的虚拟地址的标记,这时候,还是需要从高速缓存中读取页表,查找相应的物理地址。

得到物理地址后,接下来应该从高速缓存读取数据了,同样把物理地址划分为两个部分,PPNPPO。接着我们再把PPO分为两部分,CICO。根据组索引CI,我们就可以确定数据所在的组,然后我们把PPN全部当作块标记CT,来确定是组中的某一路。因此也就得到我们所需的数据所在的块了,这时候如果块是一个byte的话,就直接读取数据。但如果用一个块来存放一个byte的话,那就太浪费了,一般块的大小为几十bytes吧。这时候,我们就用之前的块偏移CO,就能得到相应的数据了。

上面的描述可能还不够清晰、直观。接下来我们分别介绍一下Intel Pentium结构和Arm结构的存储器体系。

 

 

 

四、Intel Pentium Arm 存储器体系

 

1、  Intel Pentium存储器系统(参考CSAPP

Pentium系统的地址空间为32位,处理器组件(process package)包括CPU芯片,一个L2高速缓存和一个连接它们的高速缓存总线(背板总线)。CPU芯片适当的包含了四个不同的缓存:一个数据TLB、指令TLBL1 i-cache 以及 L1 d-cachePentium中所有的缓存都是思路组相连的。见下图:摘抄自CSAPP

 

根据上图所示,TLB缓存32位的页表目录,指令TLB缓存取值单元产生产生的虚拟地址的PTE,数据TLB缓存数据的虚拟地址的TLB,页面大小可以在启动时配置成4KB或者4MB

同时我们可以看到两个L1高速缓存都为16KB,我们下面计算一下16KB是怎么得来的。其一共有128组×4路,即512个块,每块大小为32bytes,因此512×32,一共16KB大小。对于一个32位的系统,地址长度也就最大为32L1高速缓存有128组,因此组索引就需要7位。然后由于块大小为32Bytes,所以需要5位用作块偏移。总共为12位,也正好是32位地址的低12位页偏移的位数大小。高20为页号可以用作块标记。见下图:摘抄自CSAPP

 

下面给出一张图,描述的是Pentium系列处理器地址翻译的全过程:

 

通过上图,相信大家都很清楚Pentium地址翻译的流程了。PDEPTE都是32位的条目,其详细的结构可查看CSAPP中文版617页。    其中提一下PTE中的两个许可位,R/W位确定这个页面是否可读/写。U/S位,确定是否可以在用户模式下访问这个页面。

 

2、  Arm存储器系统

待续

 

 

 
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值