2017-2018-1 20155301 《信息安全系统设计基础》第11周学习总结
2017-2018-1 20155301 《信息安全系统设计基础》第11周学习总结
教材学习内容总结
虚拟存储器
-
为了更加有效地管理存储器并且少出错,现代系统提供了一种对主存的抽象概念,叫做虚拟存储器(VM)。虚拟存储器是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的完美交互,它为每个进程提供了一个大的、一致的和私有的地址空间。
虚拟存储器提供了以下几个主要的功能
1)它将主存看成是一个存储在磁盘上的地址空间同,主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,它高效地使用了主存。
2)它为每个进程提供了一致的地址空间,从而简化了存储器管理。
3)在硬件异常、汇编器、链接器、加载器、共享对象、文件和进程的设计中扮演着重要角色。
4)它保护了每个进程的地址空间不被其他进程破坏。
5)存储器让应用程序有了强大的能力,可以创建和销毁存储器片、将存储器片映射到磁盘文件的某个部分,以及与其他进程共享存储器。
-
物理地址
当CPU执行这条加载指令时,它会生成一个有效物理地址,通过存储器总线,把它传递给主存。主存取出从物理地址4处开始的4字节的字,并将它返回给CPU,CPU会将它存放在一个寄存器里。早期的PC使用物理寻址,而且诸如数字信号处理器、嵌入式微控制器以及Cray超级计算机这样的系统仍然继续使用这种寻址方式。
-
虚拟地址:CPU通过生成一个虚拟地址来访问主存,现在处理器使用虚拟寻址,虚拟存储器被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。
-
地址空间
1)地址空间是一个非负整数地址的有序集合:{0,1,2,...},在一个带虚拟存储器的系统中
2)CPU从一个有N = 2n个地址空间中生成虚拟地址,这个地址空间称为虚拟地址空间(virtual address space):{0,1,2,3,...,N-1}
3)一个地址空间的大小是由表示最大地址所需要的位数来描述的,例如一个包含N=2的n次方个地址的虚拟地址空间就叫做一个n位地址空间。
4)现代系统典型地支持32位或者64位虚拟地址空间,一个系统还有一个物理地址空间,它与系统中物理存储器的M个字节相对应
5)地址空间清楚地区分了数据对象(字节)和它们的属性(地址)。一旦认识到了这种区别,那么我们就可以将其推广,允许每个数据对象有多个独立的地址,其中每个地址都选自一个不同的地址空间。这就是虚拟存储器的基本思想。主存中每个字节都有一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址。
- 虚拟存储器作为缓存的工具
1)虚拟存储器——虚拟页VP,每个虚拟页大小为P=2^平字节
2)物理存储器——物理页PP,也叫页帧,大小也为P字节。
3)任意时刻,虚拟页面的集合都被分为三个不相交的子集
:
3.1)未分配的:VM系统还没分配/创建的页,不占用任何磁盘空间。
3.2)缓存的:当前缓存在物理存储器中的已分配页
3.3)未缓存的:没有缓存在物理存储器中的已分配页
-
dram缓存的组织结构
为了有助于清晰地理解存储中不同的缓存概念,我们将使用术语SRAM缓存来表示位于CPU和主存之间的L1、L2和L3高速缓存,并且用术语DRAM缓存来表示虚拟存储器系统的缓存,它在主存中缓存虚拟页。在存储层次结构中,DRAM缓存的位置对它的组织结构有很大的影响。回想一下SRAM比DRAM要快大约10倍,而DRAM要比磁盘快大约100000多倍。因此,DRAM缓存中的不命中比起SRAM缓存中的不命中要昂贵得多,因为DRAM缓存不命中要由磁盘来服务,而SRAM缓存不命中通常是由基于DRAM的主存来服务的。而且,从磁盘的一个扇区读取第一字节的时间开销要比从这个扇区中读连续的字节慢大约100000倍。归根到底,DRAM缓存的组织结构完全是由巨大的不命中开销驱动的。
因为大的不命中处罚和访问第一字节的开销,虚拟页往往很大,典型地是4KB~2MB。由于大的不命中处罚,DRAM缓存是全相联的,也就是说,任何虚拟页都可以放置在任何的物理页中。不命中时的替换策略也很重要,因为替换错了虚拟页的处罚也非常之高。因此,与硬件对SRAM缓存相比,操作系统对DRAM缓存使用了更复杂精密的替换算法。最后,因为对磁盘的访问时间很长,DRAM缓存总是使用写回,而不是直写。
-
页表
同任何缓存一样,虚拟存储器系统必须有某种方法来判定一个虚拟页是否存放在DRAM中的某个地方。如果是,系统还必须确定这个虚拟页存放在哪个物理页中。如果不命中,系统必须判断这个虚拟页存放在磁盘的哪个位置,在物理存储器中选择一个牺牲页,并将虚拟页从磁盘拷贝到DRAM中,替换这个牺牲页。
1)页表将虚拟页映射到物理页。
2)页表就是一个页表条目(Page Table Entry,PTE)的数组。
3)每个PTE由一个有效位和一个n位地址字段组成
-页命中
地址翻译硬件将虚拟地址作为一个索引来定位PTE2,并从存储器中读取他。因为设置了有效位,VP2是缓存在存储器中,使用PTE中的物理存储器地址构造出这个字的物理地址。
-
缺页
在虚拟存储器的习惯说法中,DRAM缓存不命中称为缺页。
缺页异常调用内核中的缺页异常处理程序,该程序会选择一个牺牲页,在此例中就是存放在PP3中的VP4。如果VP4已经被修改了,那么内核就会将它拷贝回磁盘。无论哪种情况,内核都会修改VP4的页表条目,反映出VP4不再缓存在主存中这一事实。
接下来,内核从磁盘拷贝VP3到存储器中的PP3,更新PTE3,随后返回。当异常处理程序返回时,它会重新启动导致缺页的指令,该指令会把导致缺页的虚拟地址重发送到地址翻译硬件。但是现在,VP3已经缓存在主存中了,那么页命中也能由地址翻译硬件正翻译硬件正常处理了。
-
分配页面
当操作系统分配一个新的虚拟存储器页时对我们示例页表的影响,例如调用malloc的结果
-
虚拟存储器作为存储器管理的工具
操作系统为每个进程提供了一个独立的页表,因而也就是一个独立的虚拟地址空间。
多个虚拟页面可以映射到同一个共享物理页面上。
按需页面调度和独立的虚拟地址空间的结合,对存储器的使用和管理造成了深远的影响:简化链接
简化加载
简化共享
简化存储器分配
-
虚拟存储器作为存储器保护的工具
计算机系统必须为操作系统提供手段来控制对存储器系统的访问。
PTE的三个许可位:
SUP:表示进程是否必须运行在内核模式下才能访问该页
READ:读权限
WRITE:写权限
- 地址翻译
当页面命中,CPU硬件执行的步骤:
1)处理器生成一个虚拟地址,并把它传送给MMU
2)MMU生成PTE地址,并从高速缓存/主存请求得到它
3)高速缓存/主存向MMU返回PTE
4)MMU构造物理地址,并把它传送给高速缓存/主存
5)高速缓存/主存返回所请求的数据字给处理器
页面命中完全是由硬件来处理的,与之不同的是,处理缺页要求硬件和操作系统内核协作完成:
1-3)前三步都是一样的
4)PTE中的有效位为0,所以MMU触发了一次异常,传递CPU中的控制到操系统内核中的缺页异常处理程序。
5)缺页处理程序确定出物理存储器中的牺牲页,如果这个页面被修改了,则把它换出到磁盘。
6)缺页处理程序页面调入新的页面,并更新存储器中的PTE
7)缺页处理程序返回到原来的进程,再次执行导致缺页的指令。CPU将引起缺页的虚拟地址重新发送给MMU
-
结合高速缓存和虚拟存储器
在任何既使用虚拟存储器又使用SRAM高速缓存的系统中,都存在应该使用虚拟地址还是使用讨论范围,但是大多数系统是选择物理寻址的。使用物理寻址L多个进程同时在高速缓存中有存储块和共享来自相同虚拟页面的块成为很简单的事情。而且,高速缓存无需处理保护问题,因为访问权限的检查是地址翻译过程的一部分。 -
利用tlb加速地址翻译
正如我们看到的,每次CPU产生一个虚拟地址,MMU就必须查阅一个PTE,以便将虚拟地址翻译为物理地址。在最糟糕的情况下,这又会要求从存储器取一次数据,代价是几十到几百个周期。如果PTE正碰巧缓存在L1中,那么开销就下降到1个或2个周期。然而,许多系统都试图消除这样的开销,它们在MMU中包括了一个关于PTE的小的缓存,称为翻译后备缓冲器。
TLB是一个小的、虚拟寻址的缓存,其中每一行都保存着一个由单个PTE组成的块。TLB通常有高度的相联性。如图所示,用于组选择和和行匹配的索引和标记字段是从虚拟地址中的虚拟页号中提取出来的。如果TLB有T=2的t次方个组,那么TLB索引(T田1)是由VPN的t个最低位组成的,而TLB标记是由VPN中剩余的位组成的。
- 多级页表
采用层次结构,用来压缩页表
1)以两层页表层次结构为例,好处是:
如果一级页表中的一个PTE是空的,那么相应的二级页表就根本不会存在
只有一级页表才需要总是在主存中,虚拟存储器系统可以在需要时创建、页面调入或调出二级页表,只有最经常使用的二级页表才缓存在主存中。
2)多级页表的地址翻译:
-
案例研究 Intel Core i7/Linux 存储器系统
Linux虚拟存储器系统
Linux为每个进程维持了一个单独的虚拟地址空间。
-
Linux虚拟存储器区域
Linux将虚拟存储器组织成一些区域(也叫做段)的集合。一个区域(area)就是已经存在着的(已分配的)虚拟存储器的连续片(chunk),这些页是以某种方式相关联的。例如,代码段、数据段、堆、共享库段,以及用户栈都不同的区域。每个存在的虚拟页面保存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程引用。区域的概念很重要,因为它允许虚拟地址空间有间隙。内核不用记录那些不存在的虚拟页,而这样的页也不占用存储器。磁盘或者内核本身的任何额外资源。
内核为系统中的每个进程维护一个单独的任务结构(源代码中的task_struct)。任务结构中的元素包含或者指向内核运行该进程所需要的所有信息(例如,PID,指向用户栈的指针、可执行的目标文件的名字以及程序计数器)。
一个具体区域结构包含下面的字段:
vm_start:指向这个区域的起始处。
vm_end:指向这个区域的结束处。
vm_prot:描述这个区域的内包含的所有页的读写许可权限。
vm_flags:描述这个区域内页面是与其他进程共享的,还是这个进程私有的(还描述了其他一些信息)。
vm_next:指向链表中下一个区域结构。
-
Linux缺页异常处理
-
存储器映射
Linux(以及其他一些形式的Unix)通过将一个虚拟存储器区域与一个磁盘上的对象(object)关联起来,以初始化这个虚拟存储器区域的内容,这个过程称为存储器映射(memory mapping)。虚拟存储器区域可以映射到两种类型的对象的一种:
Unix文件上的普通文件:一个区域可以映射到一个普通磁盘文件的连续部分,例如一个可执行目标文件。文件区(section)被分成页大小的片,每一片包含一个虚拟页面的初始化内容。因为按需进行页面高度,所以这些虚拟页面没有实际进行物理存储器,直到CPU第一次引用到页面(即发射一个虚拟地址,落在地址空间这个页面的范围之内)。如果区域文件区要大,那么就用零来填充这个区域的余下部分。
匿名文件:一个区域也可以映射到一个匿名文件,匿名文件是由内核创建的,包含的全是二进制零。CPU第一次引用这样一个区域内的虚拟页面时,内核就在物理存储器中找到一个合适的牺牲页面,如果该页面被修改过,就将这个页面换出来,用二进制零覆盖牺牲页面并更新页表,将这个页面标记为是驻留在存储器中的。注意在磁盘和存储器之间没有实际的数据传送。因为这个原因,映射到匿名文件的区域中的页面有时也叫做请求二进制零的页。
-
共享对象
一个对象可以被映射到虚拟存储的一个区域,要么作为共享对象,要么作为私有对象。如果一个进程将一个共享对象映射到它的虚拟地址空间的一个区域内,那么这个进程对这个区域的任何写操作,对于那些也把这个共享对象映射到它们虚拟存储器的其他进程而言也是可见的。而且,这此变化也会反映在磁盘上的原始对象中
共享对象的关键点在于即使对象被映射到了多个共享区域,物理存储器也只需要存放共享对象的一个拷贝。
私有对象是使用一种叫做写时拷贝(copy-on-write)的巧妙技术被映射到虚拟存储器中的。对于每个映射私有对象的进程,相应私有区域的页表条目都被标记为只读,并且区域结构被标记为私有的写时拷贝。
-
动态存储器分配
1)需要额外的虚拟存储器时,使用一种动态存储器分配器(dynamic memory allocator)。一个动态存储器分配器维护着一个进程的虚拟存储器区域,称为堆(heap)。在大多数的unix系统中,堆是一个请求二进制0的区域;对于每个进程,内核维护着一个变量brk,它指向堆的顶部。
2)分配器将堆视为一组不同大小的块(block)的集合来维护。每个块就是一个连续的虚拟存储器组块(chunk),要么是已分配的,要么是未分配的。
2.1)显式分配器(explicit allocator):如通过malloc,free或C++中通过new,delete来分配和释放一个块。
2.2)隐式分配器(implicit allocator):也叫做垃圾收集器(garbage collector)。自动释放未使用的已分配的块的过程叫做垃圾回收(garbage collection)。
3)malloc不初始化它返回的存储器,calloc是一个基于malloc的包装(wrapper)函数,它将分配的存储器初始化为0。想要改变一个以前已分配的块的大小,可以使用realloc函数。
4)分配器必须对齐块,使得它们可以保存任何类型的数据对象。在大多数系统中,以8字节边界对齐。
不修改已分配的块:分配器只能操作或者改变空闲块。一旦被分配,就不允许修改或者移动它。5)碎片(fragmentation)
有内部碎片(internal)和外部碎片(external)。5.1)内部碎片:在一个已分配块比有效载荷在时发生的。(如对齐要求,分配最小值限制等)
5.2)外部碎片:当空闲存储器合计起来足够满足一个分配请求,但是没有一个单独的空闲块足够大可以来处理这个请求时发生的。
-
隐式空闲链表
隐式空闲链表——空闲块通过头部的大小字段隐含地连接在一起。
-
分割空闲块
-
垃圾回收
垃圾收集器将存储器视为一张有向可达图
Mark%Sweep垃圾收集器由标记(mark)阶段和清除(sweep)阶段组成。标记阶段标记出根节点的所有可达的和已分配的后继,而后面的清除阶段释放每个被标记的已分配块。典型地,块头部中空闲的低位中的一位来表示这个块是否被标记了。
教材学习中的问题和解决过程
(一个模板:我看了这一段文字 (引用文字),有这个问题 (提出问题)。 我查了资料,有这些说法(引用说法),根据我的实践,我得到这些经验(描述自己的经验)。 但是我还是不太懂,我的困惑是(说明困惑)。【或者】我反对作者的观点(提出作者的观点,自己的观点,以及理由)。 )
- 问题1:XXXXXX
- 问题1解决方案:XXXXXX
- 问题2:XXXXXX
- 问题2解决方案:XXXXXX
- ...
代码调试中的问题和解决过程
- 问题1:XXXXXX
- 问题1解决方案:XXXXXX
- 问题2:XXXXXX
- 问题2解决方案:XXXXXX
- ...
代码托管
(statistics.sh脚本的运行结果截图)
上周考试错题总结
- 错题1及原因,理解情况
- 错题2及原因,理解情况
- ...
结对及互评
点评模板:
- 博客中值得学习的或问题:
- xxx
- xxx
- ...
- 代码中值得学习的或问题:
- xxx
- xxx
- ...
- 其他
本周结对学习情况
- [结对同学学号1](博客链接)
- 结对照片
- 结对学习内容
- XXXX
- XXXX
- ...
其他(感悟、思考等,可选)
xxx
xxx
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 200/200 | 2/2 | 20/20 | |
第二周 | 300/500 | 2/4 | 18/38 | |
第三周 | 500/1000 | 3/7 | 22/60 | |
第四周 | 300/1300 | 2/9 | 30/90 |
尝试一下记录「计划学习时间」和「实际学习时间」,到期末看看能不能改进自己的计划能力。这个工作学习中很重要,也很有用。
耗时估计的公式
:Y=X+X/N ,Y=X-X/N,训练次数多了,X、Y就接近了。
-
计划学习时间:XX小时
-
实际学习时间:XX小时
-
改进情况:
(有空多看看现代软件工程 课件
软件工程师能力自我评价表)