解决内存超载的方法
如果说计算机的存储空间足够大,足以存放所有的进程则前面的方案就可以实现多进程了,但是实际中内存空间总是不足的,现在的操作系统中开机后一般都会开启40-60个进程。
所以说前面的方案并不太合适。所以说要引入别的技术。
一种解决方案是交换技术,把一个进程全部放进内存中,运行一段时间后就会把他们放入磁盘中,空间进程都存储在磁盘中,使用的时候再把它们读取到内存中去。
另一种方案是使用虚拟内存,这种方案是将一个进程的一部分调入内存的情况下运行
一 交换技术
比如说内存中同时可以容纳a,b,c三个进程,内存够用,但是当进程d启动的时候内存不足了,而进程a处于就绪或者阻塞状态,就可以吧a交换出内存,把d交换入内存。
这种方式很好的使用的基址寄存器和界限寄存器。
但是因为分配的是连续的物理内存,所以说经过多次交换后会产生大量的内存空洞,因为每个进程分配的内存大小都不一样,并且还有一个问题是分配的内存大小为多大,
因为很多程序在运行过程中会进行内存的分配,所以说为了减少因为内存不够而产生的内存交换和移动,所以说应该为每个进程分配一些额外的内存。
二 空闲内存管理
(1)使用位图管理
使用位图的方法的时候回将内存分为几k或者几千k大小的块,每个块都用一个位标记0表示空闲,1表示已经使用,内存单元分配的越小位图越大,但是内存单元分配的越大就就会造成越大的浪费
因为进程所占用的内存不是内存单元的整数倍。
(2)使用链表管理内存
链表中节点或者是保存一个进程,或者是保存两个进程之间的空闲区,
每个链表的节点都包含一下域
该空闲区或者进程的标识,起始地址,长度,下一个节点的地址
当按照链表来管理内存的时候可以使用一下算法来为新进程分配内存
首次适配算法:遍历链表找到第一块合适的内存,可以尽可能的减少搜索
最佳适配算法:遍历链表找到最合适的一块内存,但是这样的结果是回产生一些特别小的内存空闲区,导致无法使用。
最差适配算法:找到最大的空闲内存
可以为进程区和空闲区分配不同的链表,这样的搜索效率会提高,但是这样会增加内存的复杂度,
因为分配后要从空闲区删除一个节点,为进程区添加一个节点
另外可以将空闲区的链表按照内存块的大小进行排列,这样的话就可以提高适配算法的速度。
三 虚拟内存
有些应用程序的内存过大,有可能一个程序的内存就会超过计算机的物理内存,所以说计算机的数据和代码以及堆栈不可能全部放在内存中,因此要引入别的方法
也就是虚拟内存。
虚拟内存的基本思路是每个进程都有自己的内存空间,这个空间被分为多个块,每个块称为一页或者页面。
虚拟内存适合多进程操作系统使用,每个进程的片段都保存在内存中使用,当一个进程的一部分等待读入内存的时候,可以把cpu交给另一个内存
1 分页
大部分虚拟内存给系统都采用分页技术,在虚拟内存中使用的地址都是虚拟地址,他们构成了一个虚拟地址空间。
在没有虚拟内存的计算机上系统将地址送到地址总线上直接访问物理地址,但是在虚拟内存中,系统将地址送到内存管理单元MMU(memory managerment Unit)中,MMU把虚拟地址映射为物理地址
虚拟地址空间按照固定大小划分成称为页面的内存单元。在物理内存中对应的单元称为叶框。
当程序访问虚拟内存中的一个地址的时候,把地址送到MMU中,然后解析出物理地址然后进行访问,但是有可能页面没有对应的叶框,也就是说这个页面对应的地址并没有加载到内存中来,此时引发缺页中断
此时操作系统要放弃一个叶框。
接下来MMU作如下更改,把对应该页框的页面标记为未映射,然后再把缺页的页面改为已映射,在引起缺页中断的指令重新启动的时候,把引发缺页的页面指向刚才的那个叶框
2页表
虚拟地址到物理地址的映射可以概括如下:虚拟地址被分为虚拟页号(高位)和偏移地址(低位),然后通过高位指定页面中的一页,而底位指定了所选页面的偏移量,
虚拟页号可以做页表的索引,可以指定页表项,然后通过页表项读出叶框号(如果存在的话),然后把叶框号,然后把页框号拼接到偏移地址的高位,就组成了在内存中的物理地址
页表的作用是把虚拟页面映射为叶框。
页表项的结构:
“在/不在”位,用来标记该页面是否在物理内存中
保护位 指出这个页允许什么类型的访问,读/写/执行
修改位 指出这个页面是否进行了更改
访问位 系统会在访问该页面的时候设置访问位,这个值将帮助操作系统在发生缺页中断的时候决定淘汰哪些页面,正在被访问的页面肯定不会别淘汰
高速缓存禁止位 防止页面被映射到设备寄存器中
四 加速分页过程
任何分页式系统都要考虑两个问题
1虚拟地址到物理地址的映射必须非常快
2如果说虚拟地址空间非常大则页表也会非常大
第一个问题是由于每次访问内存时,都需要访问一次或者多次访问页表
另一个问题是现在的操作系统都是32位或者64位了,设页面大小是4kb则32为的操作系统则需要包含100万条记录
转化检测缓冲区(Translation Lookaside Buffer)
假设一条指令把一个寄存器中的值复制到另一个寄存器中,则在没有采用分页时只需要访问依次内存,即从内存中读取指令,但是采用分页机制后,因为要访问页表则要引起更多次的内存访问
所以说计算机的速度被去指令或者数据的速度拖累
由于大多数程序对页面的访问总是集中在少量的页面,所以说只有很少量的表项会被大量访问,因此引入了一个设备叫做TLB
它可以将虚拟地址直接映射到物理地址,而不必再访问页表
TLB通常在MMU中,他一般会包含64个以下的表项,当访问虚拟内存单元的所指向的内存的时候,先遍历TLB如果招的所需要的内存就取出来否则就 遍历页表找到所需的页表项,然后从TLB中淘汰一个表项,用找到的新表项替代它
五 针对大内存页表
引入TLB可以加快从虚拟地址到物理地址的转换,但是对于大页表来说还是没有解决,下面是两种解法
1多级页表
32位虚拟地址被划分为10位PT1与,10位PT2域,12位偏移量
因为12位偏移量所以说页面的大小是4KB,引入多级页表可以避免把全部的页表都保存到内存中,比如说一个进程是12M,4M程序段,后边是4M数据段,最后是4M堆栈段
这样的话如果把所有的页表都放进内存中是非常浪费的,所以说引入多级页表这样就可以大大减少页表的数量,由PT1确定一级页表的页表项,
一级页表项中记载了二级页表项的地址或者页框号,现在用PT2作为访问二级页表的索引,现在因为只包含了3个4M的内存段,所以说一级页表只记载了3个二级页表的位置,并且实际内存中也只包含了3个二级页表,
这样的话实际内存中就只包含了4个页表,只包含了少量的页表项。
2 倒排页表
虽然说多级页表能够减少内存中的页表项,但是如果说是64位的系统的话地址空间是64位,页面的大小是4KB,所以说需要2^52次方的页表项,因此要换一种不同的解决方案
倒排页表是为实际内存中的每一个内存框分配一个页表项,而不是为每一个虚拟内存空间分配一个页表项,页表项中记录了哪一个进程和哪一个虚拟页面位于内存空间中。
这种方式虽然节省了大量的内存空间,但是有一个问题是从虚拟地址转换到物理地址会非常的麻烦,读取一个虚拟地址的时候必须搜索整个倒排列表,所以说非常耗时,结局方案是使用TLB
浙公网安备 33010602011771号