虚拟寻址
存储器管理单元(Memory Management Unit, MMU)是CPU上的专用硬件,CPU访存时会经过它,由它读取内存中的页表项,完成地址翻译。
缓存
结构
页表
回想SRAM缓存(位于CPU与内存间),cache中条目含有有效位,标记,内容。
把有效位和标记单独取出,再加上内容的地址,组成页表,常驻内存。
页表索引为标记。
缺页
中断处理程序返回后,把导致中断的指令重新执行。
分配页面
在磁盘上创建空间,并把更新页表相应条目,使其指向磁盘的新空间。
管理
每个进程都有独立的页表,切换进程时都重写CPU中的页表地址寄存器。
简化链接
每个进程的存储格式相同。
简化加载
加载器在页表中把0x0804800(32位)开始标记为无效,并指向目标(磁盘中的可执行文件)。
等到CPU取指或访存时调入页。
简化共享
对内核代码,C标准库,都映射到同一内存页。
简化分配
对于连续的虚拟存储页,分配的物理页可以不连续。
保护
SUP:需要内核模式(超级用户)下运行
CPU拿到物理地址的同时也能拿到权限说明,进而可以判断指令是否越权。
地址翻译
结合Cache和VM
TLB
Translation Lookaside Buffer
多级页表
i7
优化
对于Cache来说,查找标记只需PPO。故翻译VPN的同时可在Cache中查找标记。
VM: 页大小为4KB(12位),磁盘
Cache: 块大小为64B(6位),内存
虽然结构上VM位于Cache上游,但仅限于翻译过程的TLB,本质上还是处于下游。
linux
缺页中断产生后,调入物理页前会先遍历链表,
若不虚拟地址不在start和end间,产生段错误。
若在start和end间且越权(prot),触发保护异常。
映射
- 普通文件
比如a.out,虚拟地址段先映射到磁盘文件,等CPU调用到这段地址时,从磁盘调入内存,然后更新页表,使虚拟地址映射到内存。 - 匿名文件
虚拟地址段映射到内存,第一次调用时,初始化某内存页,然后更新页表,使虚拟地址映射到内存。
共享对象
- 共享对象: 所有进程都有读写权限
- 私有对象: 某进程写时要单独复制一份
fork
先复制内核信息,再共享进程信息,等任一个进程写时再分开。
mmap
重点在于选一段虚拟地址映射到物理地址,物理地址可以是内存地址,也可以是文件描述,但仅仅是映射而已,不涉及调页。
显式分配
malloc和free
mmap需给定起始地址,malloc和free默认起始地址为堆地址。
块头4字节,块大小包含块头大小。比如双字(8字节)对齐,存储5字节需要16字节(两个最小块)而不是12字节,因为最小块8字节,只是第1个块有4字节拿去当块头。
碎片
- 内部碎片:为了对齐,不满1个块大小的也要申请1个块
- 外部碎片:需要个大块,几个小块加起来满足大小但不连续
隐式空闲链
遍历整个堆去寻找空闲块
显示空闲链
在空闲块中加入前后驱指针
分离空闲链
- 简单分离存储:按块大小分类再单向连接,每个空闲链中的空闲块大小一致,不合不拆,碎片多。
- 分离适配:简单分离存储基础上,合且拆,合或拆后的结果放到其他链中。