20145319 《信息安全系统设计基础》第十四周课后总结
一 教材内容总结
基础知识
- 主要功能:
- 将主存看作是一个存储在磁盘上的地址空间的高速缓存,在主存中只保护活动的区域,并根据需要在磁盘和主存之间来回传送数据
- 为每个进程提供了一致的地址空间,从而简化了存储器管理
- 保护了每个进程的地址空间不被其它进程破坏
物理和虚拟寻址
- 物理地址(PA):它是硬件异常、硬件地址翻译、主存、磁盘文件和内核软件的交互中心
- 虚拟地址(VA):
- 地址翻译:使用虚拟寻址时,CPU通过生成一个虚拟地址VA来访问主存,这个虚拟地址在被送到存储器之前先转换成适当的物理地址,相关硬件为存储器管理单元(Memory Management Unit MMU)
地址空间
- 概念:非负整数的地址的有序集合
- 线性地址空间:地址空间中的整数是连续的
- 虚拟地址空间:CPU从一个有 N=2^n 个地址的地址空间中生成虚拟地址,这个地址空间成为称为虚拟地址空间
- 物理地址空间:和系统中物理存储器的M个字节想对应
虚拟存储器作为缓存的工具
-
虚拟页(VP):VM系统将虚拟存储器分割为大小为P的单位块作为传输单元
-
物理页(PP):将物理存储器分割为大小为P的单位块,也可以叫做页帧
-
任意时刻,虚拟页面的集合都分成三个不相交的子集:
- 未分配的:未分配的:VM系统还没分配/创建的页,不占用任何磁盘空间。
- 缓存的:当前缓存在物理存储器中的已分配页
- 未缓存的:没有缓存在物理存储器中的已分配页
-
DRAM缓存的组织结构
- 不命中处罚很大
- 是全相联的——任何虚拟页都可以放在任何的物理页中。
- DRAM缓存总是使用写回而不是直写
-
页表
- 存放在物理存储器中,将虚拟页映射到物理页
- 是一个页表条目的数组
- 页表条目(PTE)是由一个有效位和一个n为地址字段组成的
- 有效位标志了该虚拟页是否被缓存在DRAM中,如果设置了有效位,那么地址阻断就表示DRAM中相应的物理页的起始位置
-
页命中
- 当CPU读取一个字的时候,地址翻译硬件将虚拟地址作为一个索引来定位PTE,并从存储器中读取它
-
缺页
- DRAM缓存不命中
- 交换(swapping):磁盘和存储器之间传送页的活动,也称作页面调度
-
局部性的作用
- 常驻集:程序往往在一个较小的活动页面集合上工作
- 颠簸:工作集的大小超出了物理存储器的大小,就会产生这种状态--页面将不断的换进换出,程序将会变的很慢
虚拟存储器作为存储器管理的工具
- 简化链接:独立的地址空间允许每个进程的存储器映像使用相同的基本格式,而不管代码和数据实际存放在物理存储器的何处。
- 简化加载:虚拟存储器使得容易想存储器中加载可执行文件和共享文件对象。
- 简化共享:独立地址空间为操作系统提供了一个管理用户进程和操作系统自身之间共享的一致机制。
- 简化存储器分配:虚拟存储器为向用户进程提供一个简单的分配额外存储器的机制
虚拟存储器作为存储器保护的工具
- PTE总共三个许可位:
- SUP:表示进程是否必须运行在内核模式下才能访问该页
- READ:读权限
- WRITE:写权限
地址翻译
- 地址翻译是一个N元素的虚拟地址空间(VAS)中的元素和一个M元素的物理地址空间(PAS)中元素之间的映射
- n位的虚拟地址包含两个部分
- p为的虚拟地址页面偏移
- (n-p)位的虚拟页号
- 物理页面和虚拟页面都是p字节的,所以物理页面偏移和VPO是相同的
- 结合高速缓存和虚拟存储器
- 主要思路是地址翻译发生在高速缓存之前,页表条目可以缓存,就像其他的数据字一样
- 利用TLB加速地址翻译
- 翻译后备缓冲器,是一个小的、虚拟存储的缓存,其中每一行都保存着一个由单个PTE组成的块
- 多级页表
案例研究:Intel Core i7/Linux存储器系统
-
core i7地址翻译
- PTE三个权限位
- R/W位:确定内容是读写还是只读
- U/S位:确定是否能在用户模式访问该页
- XD位:禁止执行位,64位系统中引入,可以用来禁止从某些存储器页取指令
- PTE三个权限位
-
Linux虚拟存储器系统
- 每个存在的虚拟页存在某个区域中,而不属于某个区域的虚拟页是不存在的,并且不能被进程引用
- 一个具体区域结构包含的字段
- vm_start:指向这个区域的起始处
- vm_end:指向这个区域的结束处
- vm_prot:描述这个区域的内包含的所有页的读写许可权限
- vm_flags:描述这个区域内页面是与其他进程共享的,还是这个进程私有的(还描述了其他一些信息)
- vm_next:指向链表中下一个区域结构
存储器映射
-
定义:Linux通过将一个虚拟存储器区域与一个磁盘上的对象关联起来,以初始化这个虚拟存储器区域的内容的过程
-
共享对象
- 一个映射到共享对象的虚拟存储器区域叫做共享区域。
- 共享对象的关键点在于即使对象被映射到了多个共享区域,物理存储器也只需要存放共享对象的一个拷贝
-
私有对象
- 私有对象运用的技术:写时拷贝
-
fork函数
- 当fork函数被当前进程调用时,内核为新进程创建各种数据结构,并分配给它一个唯一的PID
- 当fork在新进程中返回时,新进程现在的虚拟存储器刚好和调用fork时存在的虚拟存储器相同。当这两个进程中的任一个后来进行写操作时,写时拷贝机制就会创建新页面,因此,也就为每个进程保持了私有地址空间的抽象概念
-
execve函数
- 加载并运行所需要的步骤如下:
- 删除已存在的用户区域。
- 映射私有区域。
- 映射共享区域。
- 设置程序计数器
- 加载并运行所需要的步骤如下:
-
使用map函数的用户级存储器映射
- Unix进程可以使用mmap函数来创建新的虚拟存储器区域,并将对象映射到这些区域当中
- munmap函数删除虚拟存储器的区域
动态存储器分配
-
当运行时需要额外虚拟存储器时,使用动态存储器分配器维护一个进程的虚拟存储器区域。
-
分配器有两种风格。
- 显示分配器:要求应用显式地释放任何已经分配的块。
- 隐式分配器:要求分配器检测一个已分配块何时不再被程序所使用,就释放这个块。也叫做垃圾收集器
-
malloc函数
和free函数
- 系统调用malloc函数,从堆中分配块
- 系统调用free函数来释放已分配的堆块
- 使用动态存储器分配原因:经常直到程序实际运行时,才知道某些数据结构的大小
-
分配器的要求和目标
- 显示分配器的要求:
- 处理任意请求序列
- 立即响应请求
- 只使用堆
- 对齐块
- 不修改已分配的块
- 目标:
- 最大化吞吐率:最大化存储器利用率——峰值利用率最大化
- 吞吐率:每个单位时间里完成的请求数
- 显示分配器的要求:
-
碎片
- 内部碎片:发生在一个已分配块比有效载荷大的时候,易于量化
- 外部碎片:发生在当空闲存储器合计起来足够满足一个分配请求,但是没有一个单独的空间块足以处理这个请求时发生。难以量化,不可预测
-
隐式空闲链表
- 一个块是由一个字的头部,有效载荷以及可能的一些额外的填充组成
-放置已分配的块
- 首次适配:从头开始搜索空闲链表,选择第一个合适的空闲块
- 下一次适配:从上一次搜索的结束位置开始搜索
- 最佳适配:检索每个空闲块,选择适合所需请求大小的最小空闲块
-
合并空闲块
- 合并是针对于假碎片问题的,任何实际的分配器都必须合并相邻的空闲块
- 有立即合并与推迟合并两种策略
-
分离的空闲链表
垃圾收集
- 垃圾收集器:一种动态存储分配器,它自动释放程序不再需要的已分配块,这些块被称为垃圾
- 垃圾收集器将存储器视为一张有向可达图,图的节点被分配为一组根节点和一组堆节点。当存在一条从任意根节点出发到并到达P的有向路径时,就称节点P是可达的
- makr&sweep垃圾收集器有标记阶段和清除阶段
c程序中常见与存储器有关的错误
- 间接引用坏指针
- 经典的scanf错误
scanf("%d", &val)
写作scanf("%d", val)
进程的虚拟地址没有映射到任何有意义的数据
- 读未初始化的存储器
- 栈缓冲区溢出
- 一个程序不检查输入串的大小就写入栈中的目标缓冲区就有缓冲区溢出错误,例如
gets函数
,strcpy函数
- 一个程序不检查输入串的大小就写入栈中的目标缓冲区就有缓冲区溢出错误,例如
- 假设指针和他们所指的对象是相同大小的
int **A=(int **)Malloc(n*sizeof(int*))
中如果是int*写成了int就会创建成一个int类型的数组
- 引用指针,而不是它所指向的对象
- 造成错位错误
学习进度条
代码行数(新增/累积) | 博客量(新增/累积) | 学习时间(新增/累积) | 重要成长 | |
---|---|---|---|---|
目标 | 5000行 | 30篇 | 400小时 | |
第一周 | 0/0 | 1/1 | 20/20 | 学习常用linux命令 |
第二周 | 100/100 | 1/2 | 20/40 | 学习vim,gdb等用法 |
第三周 | 100/200 | 1/3 | 15/55 | |
第四周 | 0/300 | 0/3 | 10/65 | |
第五周 | 100/400 | 1/4 | 15/80 | 重温了汇编相关知识 |
第六周 | 0/400 | 1/5 | 15/95 | 学习了Y86 |
第七周 | 100/500 | 1/6 | 15/110 | 学习了存储器相关知识 |
第八周 | 0/500 | 2/8 | 20/130 | 复习 |
第九周 | 150/650 | 2/10 | 15/145 | 学习了I/O相关知识 |
第十周 | 300/950 | 2/12 | 20/165 | 学习了linux命令代码 |
第十一周 | 200/1150 | 3/15 | 20/185 | 学习了异常流相关知识 |
第十二周 | 200/1350 | 3/18 | 20/205 | 复习I/O,fork相关代码 |
第十三周 | 150/1500 | 2/20 | 20/225 | 学习了并发,WEB相关知识 |
第十四周 | 150/1650 | 1/21 | 20/245 | 学习虚拟存储器相关知识 |