信息安全系统设计基础第十四周学习总结
虚拟存储器
物理和虚拟地址
物理地址-> 物理寻址
虚拟地址 -> 地址翻译 -> 存储器管理单元 -> 虚拟寻址
地址空间
虚拟地址空间 N=2^n
物理地址空间 M=2^m
主存中每个字节都有一个选自虚拟地址空间的虚拟地址和一个选择物理空间的物理地址。
虚拟存储器作为缓存的工具
虚拟页面的集合都分为三个不相交的子集:
未分配的、缓存的、未缓存的
DRAM缓存的组织结构
页表(页表条目的数据结构)
页命中
缺页
分配页面
局部性:活动页面上的工作集(常驻集)
虚拟存储器作为存储器的管理工具
VM简化了链接和加载、代码和数据共享,以及应用程序的存储器分配。
- 简化链接
- 简化加载
- 简化共享
- 简化存储器分配
虚拟存储器作为存储器保护的工具
每个PTE添加三个许可位,SUP位表示进程是否必须运行在内核(超级用户)模式下才能访问页面。READ位和WRITE位控制对页面的读和写的访问。
地址翻译
地址翻译是一个N元素的虚拟地址空间中的元素和一个M元素的物理地址中元素之间的映射。
页命中CPU执行步骤
- 第一步:处理器生成一个虚拟地址,并把它传给MMU
- 第二步:MMU生成PTE地址,并从高速缓存/主存请求得到它
- 第三步:高速缓存/主存向MMU返回PTE
- 第四步:MMU构造物理地址,并把它传送给高速缓存/主存
- 第五步:高速缓存/主存返回所请求的数据字给处理器
缺页
- 第一步:处理器生成一个虚拟地址,并把它传给MMU
- 第二步:MMU生成PTE地址,并从高速缓存/主存请求得到它
- 第三步:高速缓存/主存向MMU返回PTE
- 第四步:PTE有效位是零,MMU触发了一次异常,传递CPU中的控制到操作系统内核中的缺页异常处理程序
- 第五步:缺页处理程序确定出物理存储器中的牺牲页。如果该页面已经修改,则把它换出到磁盘
- 第六步:缺页处理程序调入新的页面,并更新存储器中的PTE
- 第七步:缺页处理程序返回原来的进程,再次执行导致缺页的指令。
结合高速缓存和虚拟存储器
利用TLB加速地址翻译
- 第一步:CPU产生一个虚拟地址
- 第二步和第三步:MMU从TLB中取出相应的PTE
- 第四步:MMU将这个虚拟地址翻译成一个物理地址,并且将它发送到高速缓存/主存
- 第五步:高速缓存/主存将所请求的数据字返回给CPU
多级页表
端到端的地址翻译
存储器映射
虚拟存储器区域可以映射到两种类型的对象中的一种:
- Unix文件系统中的普通文件
- 匿名文件
共享对象
fork函数
execve函数
使用nmap函数的用户级存储器映射
动态存储器分配
分配器两种基本风格:
显式分配器
隐式分配器
malloc和free函数
#include<stdio.h>
void *malloc(size_t size);
返回:若成功则为指针,若出错则为NULL
#include<stdio.h>
void *sbrk(intptr_t incr);
返回:若成功则为旧的brk指针,若出错则为-1
分配器的要求和目标
处理任意请求序列
立即响应请求
只使用堆
对齐块(对齐要求)
不修改已分配的块
目标:
- 最大化吞吐率
- 最大化存储器利用率(峰值利用率)
碎片:
内部碎片、外部碎片
实现问题:空闲块组织、放置、分割、合并
隐式空闲链表
放置已分配的块(放置策略、首次适配、下一次适配和最佳适配)
分割空闲块
获取额外的堆存储器
合并空闲块
带边界标记的合并
实现一个简单的分配器
- 一般分配器设计
- 操作空闲列表的基本常数和宏
- 创建初始空闲链表
- 释放和合并块
- 分配块
显示空闲链表
方法一:后进先出的顺序维护链表
方法二:按照地址顺序维护链表
分离的空闲链表
两种方法:简单分离存储和分离适配(伙伴系统)
垃圾收集
垃圾收集器(可达图、根节点、堆节点)
Mark&Sweep的垃圾收集器
由标记阶段和清除阶段组成
C程序的保守Mark&Sweep
C程序的Mark&Sweep收集必须是保守的根本原因是C语言不会用类型信息来标记存储器位置。
C程序中常见的与存储器有关的错误
间接引用坏指针
传递给scanf一个格式串和变量的地址
scanf(“%d",&val)
scanf ("%d", val)
读未初始化的存储器
允许栈缓冲区溢出
假设指针和它们指向的对象是相同大小的
造成错位错误
引用指针,而不是它所指向的对象
误解指针运算
引用不存在的变量
引用空闲堆块中的数据
引起存储器泄露
参考资料:《深入理解计算机系统》