L20 内存使用与分段
:::info 管理内存的原因:
- 计算机取指执行,指令在内存中
- 使用绝对地址不方便,因为程序载入时,并不确定会放在哪里
- 因此决定使用逻辑地址的机制:段地址+偏移地址,将程序中的地址看作逻辑地址
但是在多进程的情况下,段地址也会经常发生改变,用什么机制来克服? :::
重定位
用逻辑地址来替代绝对地址
是么时候完成重定位?编译时重定位的程序只能放在内存固定位置
- 载入时重定位的程序一旦载入内存就不能动了
- 应该是运行时完成重定位
why
:::info
多进程应用仍然需要频繁的交换!
:::
每个进程有各自的基地址,放在PCB中
- 执行指令时第一步先从PCB中取出这个基地址
-
程序分段
:::info why 程序分段
因为不同的程序段有不同的特性:代码段只读、变量段大小固定、堆栈区会动态变化……
分段进行管理内存,更加高效! :::
如上图所示,将对应的代码段分区域放入内存 这里就引出了LDT表
LDT表存着不同的段对应的基址,通过查找LDT表可以获得想要的段的某个偏移地址下的内容。
:::tips
实际使用时是将GDT和LDT结合使用的
:::
GDT:操作系统对应的段表,存进程的
LDT:每个进程对应的段表,存不同代码段的基地址。
L21 内存分区与分页
:::info 新的问题:如何分配空闲的内存
- 固定分区
-
可变分区
可以通过建立分区表的机制来控制 :::info 但是仍有问题 存在内存碎片
一旦碎片过多需要内存紧缩(重新把内容集中移动,这样耗时很大) ::: :::tips 解决方式:从连续到离散!—内存分页 :::
例如在Linux0.11中,4k分成一页(正好3位);对所需要的空间,计算其大小并向上取整;
- 这样最多浪费的空间不过4k
- 上图中页仍是相对or逻辑的页,而页框是实际物理上分的页
:::tips
页表中存了页号(可以理解为逻辑地址)和页框号的对应;
逻辑地址是由页号和偏移量组成,先根据页号找到实际的页框,然后根据偏移量得到实际的地址;
:::
L22 多级页表与快表
:::info 问题:页太小了页表就变大了 :::
- 为了避免空间浪费页应该尽可能小
- 但是这样页表会变得非常大
2^20个页表项都得放在内存中,需要4M内存;系统中并发10个进程,就需要 40M内存
方法1:只放用到的页表
实际上大部分的逻辑地址根本用不到
不连续怎么从逻辑页号到物理页号?
- 需要依次比较查找,需要耗费很多时间
-
方法2:多级页表
一个页目录能控制4M的内存,此处不需要的页目录不会留存!
:::tips 牺牲是什么? -
快表(TLB)
TLB是一组相关联的快速存储,是寄存器 :::tips 存近期访问的页号! ::: :::info 通过硬件比对,一次查找即可得到的!
若未查到,则仍是使用多级页表查找,并将查到的内容放到快表中。 ::: TLB命中时效率会很高,未命中时效率降低
要想真正实现“近似访存1次” ,TLB的命中率应该很高 TLB越大越好,但TLB很贵,通常只有[64,1024] :::info whyTLB可以相对较小【64,1024】?程序的访问具有局部性
- 程序多体现为循环和顺序结构。 :::