前面我们分析了虚拟地址和物理地址
我们这里进行一个简单的分析
这个是程序运行时的地址映射
那么这些碎片,我们现在的操作系统究竟如何处理呢?
我们再引入一个实际问题
我们如何把右边的进程p塞入左边的内存空间里面
有一种方法将p5kill掉,那么p就可以插入,但这种方法绝对不是首选。
我们可以将p进程分为几块塞入内存空间里面
但是如果我们需要运行这个进程需要有一个记录,记录p进程的各个碎片是怎样分布在内存里面的。
这样就引出了我们的分页和分段机制了
1.解决内存碎片,将进程分片存放
因为我们写程序的时候是分段(函数、变量、数组等)写的
我们可以将这些东西分段存放
我们对于分段的寻址是需要段id+段内位移地址
那么我们怎么将逻辑地址转化为物理地址
我们分段表内存储段id+段内偏移+段内最大长度
先拿出段内位移然后根据所在的段号进行判断,判断失败报错;成功,用基址加上短萼你位移取出物理内存地址。
我们看例题
第一题解题方法:
main那条语句为pc寄存器存储的地址,我们可以看到0x240为此地址的虚地址
那么我们可以画出
0x0240填入逻辑地址二进制为
0000 0010 0100 0000
又物理地址等于基址+逻辑地址
最前面的2bits 00 代表段号,那么我们可以得到段号为code(0)基址为0x4000
根据等式可以得到0x4000+0x0240=0x4240
第二题第一步我们可以大致判断是将一个地址存入一个变量或一个寄存器里面(目前来看没啥用)。我们根据pc+4,且前面2bits的段号并没有变(基址还为0x4000)可以得到0x4000+0x0240+0x0004=0x4244
第三题第一步也是存储了一个地址,但他这里注释了是返回地址(对这题来说也没啥用)
,move 0x0360转换
0000 0000 0011 0110 0000
这里可以得到段号还是0,也就是说基址还是0x4000
那根据前面的算是可以得到0x4000+0x0360=0x4360
第四题大家可以自行判断
答案为:0x4364
最后一题,我们发现这个是将a0的地址读一个byte并写入t0,第一题我们知道了a0里的内容为 0x4050
0x4050转化为二进制
0100 0000 0101 0000
这是一个虚拟地址,这个区间是属于段号1的(也可以根据段号判断这里是01)
我们得到段号
01(舍掉)00 0000 0101 0000 舍掉的补0(因为前两个bits代表段号)
偏移量等式逻辑地址减去前面两位bits补0
0000 0000 0101 0000 得到偏移地址0x050
那么我们要得到真实地址需要0x4800 + 0x0050 = 0x4850
其实我们可以分析这段代码是读取一个字符串,当然后面还有很多大家可以自己看下这个代码
分页机制
因为段的大小是不等的,只不过是分的更小一些,那么产生的碎片肯定是会更小的
所以分段对于外部碎片问题并没有完全解决
这里有个基本单元叫做帧也有叫页框的,内存划分的固定大小的区块(注意这里是固定大小不是大小不等),但里面可以离散存放。将进程分成一条一条的整个叫做页面
我们将页面内的每条存入内存中任意空闲的页框(帧)当中
再将他们记录下来
存这个记录的叫做page table 页表
原理和分段是差不多的
那么我们如何得到物理地址呢?
根据下面图我们算下要找page号为0的进程条的物理地址
查页表发现page号为0的这条数据存入了帧号为5的区域
我们根据frame no——5来从内存中查找定位到一块区域(这里可以看到每个页大小为4bytes),注:帧大小和页大小一样
我们再根据页内位移定位物理位置
这里我们可以得到实际的参与运算的参数为 frame no. * page size + 页内位移 = 物理地址
第一个|0|3|我们可以得到5*4+3=23 因为是从0开始的所以这里要减1
第二个|2|3|我们可以得到2*4+3=11-1=10
第三个|1|3|我们可以得到0*4+3=3-1=2
这里可以看出这个帧(页)的大小和磁盘的block块有异曲同工之妙
这里地址
页数2^(m-n),页尺寸为2^n,整个地址长度为m
页和段分区的特点对比,大家自信分析一下