20145203 《信息安全系统设计基础》第十四周学习总结

第九章 虚拟存储器

虚拟存储器是计算机系统最重要的概念之一,它是对主存的一个抽象

三个重要能力:

  • 它将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,高效的使用了主存
  • 它为每个进程提供了一致的地址空间,从而简化了存储器管理
  • 它保护了每个进程的地址空间不被其他进程破坏

第一节 物理和虚拟寻址

①物理地址

计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组,每字节都有一个唯一的物理地址PA

②虚拟地址

虚拟存储器被组织为一个由存放在磁盘上的N个连续的字节大小的单元组成的数组。

第二节 地址空间

1.地址空间

地址空间是一个非负整数地址的有序集合:

{0,1,2,……}

2.线性地址空间

地址空间中的整数是连续的。

3.虚拟地址空间

CPU从一个有 N=2^n 个地址的地址空间中生成虚拟地址,这个地址空间成为称为虚拟地址空间。

4.地址空间的大小

由表示最大地址所需要的位数来描述。

N=2^n:n位地址空间

主存中的每个字节都有一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址。

第三节 虚拟存储器作为缓存的工具

任意时刻,虚拟页面的集合都被分为三个不相交的子集:

  • 未分配的:VM系统还没分配/创建的页,不占用任何磁盘空间。
  • 缓存的:当前缓存在物理存储器中的已分配页
  • 未缓存的:没有缓存在物理存储器中的已分配页

1.DRAM缓存的组织结构

需要知道,这种缓存结构:

  • 不命中处罚很大
  • 是全相联的——任何虚拟页都可以放在任何的物理页中。
  • 替换算法精密
  • 总是使用写回而不是直写。

2.页表

页表是一个数据结构,存放在物理存储器中,将虚拟页映射到物理页。

页表就是一个页表条目PTE的数组,组成为:

有效位+n位地址字段

①如果设置了有效位:

地址字段表示DRAM中相应的物理页的起始位置,这个物理页中缓存了该虚拟页

②如果没有设置有效位:

(1)空地址:表示该虚拟页未被分配

(2)不是空地址:这个地址指向该虚拟页在磁盘上的起始位置。

3.缺页

几个定义:

  • 缺页:就是指DRAM缓存不命中。
  • 缺页异常:会调用内核中的缺页异常处理程序,选择一个牺牲页。
  • 页:虚拟存储器的习惯说法,就是块
  • 交换=页面调度:磁盘和存储器之间传送页的活动
  • 按需页面调度:直到发生不命中时才换入页面的策略,所有现代系统都使用这个。

4.虚拟存储器中的局部性

局部性原则保证了在任意时刻,程序将往往在一个较小的活动页面集合上工作,这个集合叫做工作集/常驻集

第四节 虚拟存储器作为存储器管理的工具

  • 操作系统为每个进程提供了一个独立的页表,也就是一个独立的虚拟地址空间。
  • 抖个虚拟页面可以映射到同一个共享物理页面上。
  • 存储器映射:将一组连续的虚拟页映射到任意一个文件中的任意位置的表示法。

VM简化了链接和加载、代码和数据共享,以及应用程序的存储器分配。

第五节 虚拟存储器作为存储器保护的工具

PTE的三个许可位:

  • SUP:表示进程是否必须运行在内核模式下才能访问该页
  • READ:读权限
  • WRITE:写权限

第六节 地址翻译

地址翻译就是一个N元素的虚拟地址空间VAS中的元素和一个M元素的物理地址空间PAS中元素之间的映射。

1.当页面命中时,CPU动作:

  • 处理器生成虚拟地址,传给MMU
  • MMU生成PTE地址,并从高速缓存/主存请求得到他
  • 高速缓存/主存向MMU返回PTE
  • MMU构造物理地址,并把它传给高速缓存/主存
  • 高速缓存/主存返回所请求的数据给处理器。

2.处理缺页时:

  • 处理器生成虚拟地址,传给MMU
  • MMU生成PTE地址,并从高速缓存/主存请求得到他
  • 高速缓存/主存向MMU返回PTE
  • PTE中有效位为0,触发缺页异常
  • 确定牺牲页
  • 调入新页面,更新PTE
  • 返回原来的进程,再次执行导致缺页的指令,会命中

3.利用TLB加速地址翻译

TLB:翻译后备缓冲器,是一个小的、虚拟存储的缓存,其中每一行都保存着一个由单个PTE组成的块

步骤:

  • CPU产生一个虚拟地址
  • MMU从TLB中取出相应的PTE
  • MMU将这个虚拟地址翻译成一个物理地址,并且将它发送到高速缓存/主存
  • 高速缓存/主存将所请求的数据字返回给CPU

4.多级页表

多级页表——采用层次结构,用来压缩页表

①以两层页表层次结构为例,好处是:

  • 如果一级页表中的一个PTE是空的,那么相应的二级页表就根本不会存在
  • 只有一级页表才需要总是在主存中,虚拟存储器系统可以在需要时创建、页面调入或调出二级页表,只有最经常使用的二级页表才缓存在主存中。

②多级页表的地址翻译:

第七节 案例研究

一、Core i7地址翻译

在这里,PTE有三个权限位:

  • R/W位:确定内容是读写还是只读
  • U/S位:确定是否能在用户模式访问该页
  • XD位:禁止执行位,64位系统中引入,可以用来禁止从某些存储器页取指令

还有连个缺页处理程序涉及到的位:

  • A位,引用位,实现页替换算法
  • D位,脏位,告诉是否必须写回牺牲页

二、Linux虚拟存储器系统

Linux为每个进程维持了一个单独的虚拟地址空间

内核虚拟存储器包括:内核中的代码和数据结构。

一部分区域映射到所有进程共享的物理页面

另一部分包含每个进程都不相同的数据。

三、Linux虚拟存储器区域

区域:就是已分配的虚拟存储器的连续片。

区域的例子:

  • 代码段
  • 数据段
  • 共享库段
  • 用户栈
  • ……

一个具体区域的区域结构包括:

  • vm_start:指向起始处
  • vm_end:指向结束处
  • vm_prot:描述这个区域包含的所有页的读写许可权限
  • vm_flags:是共享的还是私有的
  • vm_next:指向下一个区域

四、Linux缺页异常处理

1.虚拟地址A是否合法?

不合法,触发段错误,终止进程

合法,进入下一条

2.存储器访问是否合法?即,是否有权限?

不合法,触发保护异常,终止程序

合法,进入下一条

3.这时,是针对合法的虚拟地址进行合法的操作。所以:选择一个牺牲页面,如果被修改过就换新的并更新页表。

第八节 存储器映射

即指Linux通过将一个虚拟存储器区域与一个磁盘上的对象关联起来,以初始化这个虚拟存储器区域的内容的过程。

映射对象:

1.Unix文件系统中的普通文件

2.匿名文件(全都是二进制0)

第九节 动态存储器分配

1.堆:

是一个请求二进制0的区域,紧接在未初始化的bss区域后开始,并向上(更高的地址)生长。有一个变量brk指向堆的顶部

2.分配器的两种基本风格:

a.显示分配器-malloc和free
b.隐式分配器/垃圾收集器

3.分配器的要求和目标:

①要求

  • 处理任意请求序列
  • 立即响应请求
  • 只使用堆
  • 对齐块
  • 不修改已分配的块

②目标:

  • 最大化吞吐率(吞吐率:每个单位时间里完成的请求数)
  • 最大化存储器利用率——峰值利用率最大化

4.碎片

虽然有未使用的存储器,但是不能用来满足分配请求时,发生这种现象。

①内部碎片

发生在一个已分配块比有效载荷大的时候

易于量化。

②外部碎片

发生在当空闲存储器合计起来足够满足一个分配请求,但是没有一个单独的空间块足以处理这个请求时发生

难以量化,不可预测。

5.隐式空闲链表

空闲块通过头部中的大小字段隐含地连接着,分配器可以通过遍历堆中所有的块,从而间接地遍历整个空闲块的集合。

需要:特殊标记的结束块。

系统对齐要求和分配器对块格式的选择会对分配器上的最小块大小有强制的要求。

6.放置已分配的块——放置策略

①首次适配

从头开始搜索空闲链表,选择第一个合适的空闲块

②下一次适配

从上一次搜索的结束位置开始搜索

③最佳适配

检索每个空闲块,选择适合所需请求大小的最小空闲块

7.合并空闲块
8.
合并是针对于假碎片问题的,任何实际的分配器都必须合并相邻的空闲块。

有两种策略:

  • 立即合并
  • 推迟合并

第十节 垃圾收集

垃圾收集器是一种动态存储分配器,它自动释放程序不再需要的已分配块,这些块被称为垃圾,自动回收堆存储的过程叫做垃圾收集

1.垃圾收集器将存储器视作一张有向可达图,只有当存在一条从任意根节点出发并到达p的有向路径时,才说节点p是可达的,而不可达点就是垃圾。

2.Mark&Sweep垃圾收集器

有两个阶段:

  • 标记:标记出根节点的所有可达的和已分配的后继
  • 清楚:释放每个未被标记的已分配块。

相关函数:

ptr定义为typedef void *ptr
  • ptr isPtr(ptr p):如果p指向一个已分配块中的某个字,那么就返回一个指向这个块的起始位置的指针b,否则返回NULL
  • int blockMarked(ptr b):如果已经标记了块b,那么就返回true
  • int blockAllocated(ptr b):如果块b是已分配的,那么久返回ture
  • void markBlock(ptr b):标记块b
  • int length(ptr b):返回块b的以字为单位的长度,不包括头部
  • void unmarkBlock(ptr b):将块b的状态由已标记的改为未标记的
  • ptr nextBlock(ptr b):返回堆中块b的后继

3.C保守的Mark&Sweep——平衡二叉树

根本原因是C语言不会用类型标记来标记存储器位置。

第十一节 C程序中常见的与存储器有关的错误

1.间接引用坏指针

常见错误:

——scanf错误

2.读未初始化的存储器

常见错误:

——假设堆存储器被初始化为0

3.允许栈缓冲区溢出

常见错误:

——缓冲区溢出错误

4.假设指针和它们指向的对象是相同大小的

在远处起作用action at distance

5.造成错位错误

6.引用指针,而不是它所指向的对象

7.误解指针运算

8.引用不存在的变量

9.引用空堆块中的数据

10.引起存储器泄露

其它(思想、感悟)

这一章学完,整本书的学习也算是差不多结束了,其实有很多东西都只是简单的过了一遍,学到的都只是皮毛,过一段时间很容易就会忘记了,要想学到真本事,还得自己反反复地去琢磨去看去理解,还有更多的东西值得我们去学习。

本周代码托管截图

代码链接

学习进度条

代码行数(新增/累积) 博客量(新增/累积) 学习时间(新增/累积) 重要成长
目标 5000行 30篇 400小时
第一周 150/150 1/2 20/20
第二周 200/350 1/2 24/44
第三周 150/500 1/3 20/64
第五周 300/800 1/4 15/79
第六周 500/1300 1/5 20/99
第七周 200/1500 1/6 21/120
第九周 210/1710 1/9 10/130
第十周 530/2240 2/11 20/150
第十一周 900/3140 1/12 30/180
第十三周 1100/4240 1/17 30/210
第十四周 500/4720 1/18 20/230

参考资料

posted @ 2016-12-18 23:28  20145203盖泽双  阅读(204)  评论(2编辑  收藏  举报