内存使用与分段
内存使用
- 内存使用的第一个问题:
**重定位:**修改程序中的地址(相对地址)
重定位的时机:- 编译时:编译时就需要知道哪段内存是空闲且实际必须使用该处内存,预留该处内存(一些嵌入式系统烧录进去就不动了,可以使用这种方法)
- 载入时:重定位的程序一旦载入内存就不能移动
- 运行时重定位
**地址翻译:**运行每条指令时重新计算实际的物理地址
基址放在PCB中,每个进程有各自的基址
计算过程由MMU硬件支持
内存分段
不同段的特点不同,需要每个段独立管理。
定位具体的指令或数据时利用所处段的段号找到段基址+段内偏移获得。
OS的GDT表(操作系统对应的段表)记录了操作系统的每一个段的基址;
应用程序在PCB中有LDT表(段表)记录该进程的每一个段的基址;
寄存器是LDTR,指向LDT表的位置。
内存分区与分页
内存分区
- 内存如何分割(分区)?——
固定分区可变分区 - 管理可变分区的内存——分区表,记录空闲分区和已分配分区
- 某个段新申请内存:
- 首先适配(随机)
- 最佳适配(分配最接近申请大小的空闲内存)
- 最差适配(分配与申请大小差距最大的空闲内存)
内存分页
- 可变分区容易引发内存碎片问题,空间利用率下降
- 如果采用内存紧缩(移动内存中的内容,将空闲内存分区合并)——需要花费大量的时间,并且整个系统不可用
- 解决的办法——内存分页
- 页表中存储与页号相对应的页框号,并且记录读写权限,PCB中存储着对应进程的页表
- 每个页表占四个字节4Bytes
- CR3寄存器指向页表的位置
多级页表与快表
多级页表
- 页表使用的问题:占用内存
一页空间通常为4K,32位机能寻址的空间是 2 32 2^{32} 232Bytes,总共需要有 2 32 / 2 12 = 2 20 2^{32}/2^{12}=2^{20} 232/212=220个页,每个页占4Bytes内存,每个进程存储的页表占4M内存,实际上可能有上百个进程,就需要100M内存
实际上大部分逻辑地址根本不会用到- 第一种尝试:只存放用到的页
- 后果:页号不连续,每次使用内存的时候需要在也表中查找。
为了取出指定内存中的内容,需要取出 l o g ( 2 20 ) log(2^{20}) log(220)次页表中的内容(假设用二分查找),增加了很多次访存。
- 后果:页号不连续,每次使用内存的时候需要在也表中查找。
- 第二种尝试:多级页表,页目录表(章)+页表(节)
跳过了一些空的页表,只存储一个章的标题(占4Bytes)而省略节标题(4K),有大量的空页表,从而节省空间。图中示例 2 10 2^{10} 210个章只用到了3章,其它的都将4K空间节省到4Bytes空间。
- 第一种尝试:只存放用到的页
- 多级页表带来的问题:增加访存
实际上,每多一级页表,访问内存时就会多增加一次访存,速度降低。- 快表(TLB):记录最近使用的逻辑地址对应的物理地址
- 特点:存储地址不连续,但是不需要软件二分查找,而是通过硬件机制(相联快速存储)一次必对命中查找的内容
- 每次访问内存时先查快表,快表未命中时再查多级页表
- 有效性与TLB的命中率有关:
由于程序的地址访问存在局部性,经常在小范围内存中不断执行,所以TLB命中率一般都很高。