赞
踩
进程在系统上的运行分为两个级别,用户态和内核态。
用户态的进程可以直接读取用户程序的数据,系统态的进程可以直接访问计算机的任何资源,不受限制。
运行的应用程序基本都是运行在用户态,如果调用操作系统提供的系统态的子功能,就需要系统调用。
系统调用,按功能大致分为:
负责内存空间的分配与回收(C++中的malloc函数申请内存,free函数释放内存)
从逻辑上对内存空间进行扩充(如4GB内存运行60GB大小的游戏)
负责进行地址转换,也就是把逻辑地址转换成相应的物理地址
内存保护。保证各进程在各自存储空间内运行,互不干扰。
如果没有虚拟地址空间,程序直接访问和操作的都是物理内存。这样会带来两个主要问题:
内存管理机制分为连续管理方式(指为一个用户程序分配一个连续的内存空间)和非连续管理方式(指允许一个程序使用的内存有着不相邻的分布)
连续分配管理方式
分块管理
把内存分为大小相等且固定的几个块,每个进程占用其中的一个。如果进程很小的话,会浪费大量的空间。块式管理已经被淘汰。
非连续分配管理方式
分页管理
把内存分为若干个很小的页面,相比分块,划分的力度更大。分页管理提高了内存利用率,减少内存碎片。
分页管理通过页表对应逻辑地址和物理地址。
分页管理虽然提高了内存利用率,但是“页”无实际意义。
分段管理
把内存分为几个大小不固定的、有意义的段,每个段定义了一组逻辑信息。例如,主程序段Main、子程序段X、数据段D、栈段S等。
分段管理通过段表对应逻辑地址和物理地址。
段页式管理
段页式管理结合了分段管理和分页管理的优点。把主存先分成若干段,每个段又分成若干页。段与段之间、段的内部(因为是页)都是离散的。
页框:将内存空间分为一个个大小相等的分区(比如每个分区4KB),每个分区就是一个“页框”,或者称为“页帧”、“内存块”、“物理块”
页框号:每个页框有一个编号,称为“页框号”,或者“页帧号”、“内存块号”、“物理块号”。页框号从0开始
页/页面:
将用户进程的地址空间也分为与页框大小相等的一个个区域,称为“页”或“页面”。每个页面也有一个编号,即“页号”,页号也是从0开始。
一个进程的最后一个页可能并没有页框那么大(这样最后一个页放在页框中会有内部碎片)。因此页框不能太大,避免产生过大的内部碎片。
操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。
各个页面不必连续存放,也不必按照顺序,可以放到不相邻的页框中。
分页管理中,每个页表项由“页号”和“内存块号”组成。
内存管理单元(MMU)管理着逻辑地址和物理内存的转换,其中页表(Page Table)存储着页(程序地址空间)与页框(物理内存)的映射表。
下图页表存放着16个页,这16个页要用4个比特位来进行索引定位。
例如,对于虚拟地址(0010 0000 0000 0100),前4位是存储页面号(0010)2,后12位(0000 0000 0100)是存储偏移量。
根据页面号读取页表中对应表项(2)的内容(1101)。页表项内容的前3位表示内存块号,最后一位表示是否存在于内存中(0表示不存在,1表示存在)。
拼接页表项内容的前三位(内存块号,110)和虚拟地址中的后12位(存储偏移量,0000 0000 0100),得到物理地址(110 0000 0000 0100)。
根据得到的物理地址访问内存空间。
快表的引入,是为了加快逻辑地址(虚拟地址)到物理地址转换的速度。
在引入快表之前,由逻辑地址访问内存的过程如下:
这个过程是需要两次直接访问内存的,所以为了加快这个访问速度,引入了快表。
快表可以认为是一个高速缓冲存储器(Cache),内容是页表的一部分或者全部内容,和页表的功能是一样的,只不过比在内存中的页表访问速度要快很多。
由于采用页表做地址转换,读写内存数据时 CPU 要访问两次主存。有了快表,有时只要访问一次高速缓冲存储器,一次主存,这样可加速查找并提高指令执行速度。
被访问的内存块很可能在短时间内再次被访问,可能程序在一段时间内会多次访问同一个页表项。
所以在每次访问页表项时,先在快表里查询是否有该页表项,如果没有再去页表中查询,并把查询的页表项存入快表。
如果快表满了,就根据一些策略把其中的一些页表项淘汰掉,再把新查询的页表加进去。
总结:使用快表之后的地址转换流程如下:
多级页表主要是为了避免把全部页表一直放在内存中占用过多空间的问题,特别是那些根本就不需要的页表就不需要保留在内存中。属于时间换空间。
单级页表存在的问题:
两级页表,将全部的页表项分组,使得每组的页表项刚好能够装入一个内存块,让各组页表项(二级页表)可以离散地分配在各个内存块中,同时为了记录二级页表的顺序,通过一个“页目录表”来映射二级页表的页号和二级页表存放的内存块号。
两级页表的引入,使得虚拟地址的结构也要发生相应的变化:一级页号+二级页号+页内偏移量
两级页表的地址转换:
注意,采用多级页表机制时,各级页表的大小不能超过一个页面。
段长大小是不固定的,但是段表项长度是固定的,不要混淆。
段页式管理中,每个段对应一个段表项,每个段表项由段号、页表长度、页表存放块号(页表起始地址)组成。每个段表项长度相等,段号是隐含的。
分段管理中,每个段表项由段号、段长、基址组成。
段页式管理中以及分页管理中,每个页面对应一个页表项,每个页表项由页号、页面存放的内存块号组成。
Note:段页式管理中的段表项结构与分段管理中的段表项结构不同,但段页式管理中的页表项结构与分页管理中的页表项结构相同。
一个进程对应一个段表,但是一个进程有可能对应多个页表。
分页
单级页表
多级页表(n级)
分段
段页式
快表
实现虚拟内存,操作系统需要在传统的非连续分配存储管理方式的基础上,再增加两个主要功能:
实现虚拟内存的三种主要方式为:
请求分页存储管理
请求分段存储管理
原理和请求分页存储管理相似,不过是把页面换成段
请求段页式存储管理
不管是上面哪种实现方式,一般都需要:
请求分页存储管理中的页面置换算法。
页面的换入、换出需要磁盘IO,会有较大的开销,因此好的页面置换算法应该追求更少的缺页率。
最佳置换算法,每次选择淘汰的页面将是以后永不使用或者在最长时间内不再被访问的页面,这样可以保证最低的缺页率。
实际上,只有在进程执行的过程中才能知道接下来会访问到的是哪个页面,无法提前预判页面访问序列。因此,最佳页面置换算法是无法实现的。
先进先出置换算法,每次选择淘汰的页面是最早进入内存的页面。
实现算法:把调入的页面根据调入的先后顺序排成一个队列,需要换出页面时选择队头页面换出即可。
队列的最大长度限制取决于系统为进程分配了多少个内存块。
最近最久未使用置换算法,每次淘汰的页面是最近最久未使用的页面。
实现方法:LRU赋予每个页面一个访问字段,用访问字段记录该页面自上次被访问以来所经历的时间T。当需要淘汰一个页面时,选择现有页面中T值最大的,即最近最久未使用的页面。
最少使用页面置换算法(LFU,Least Frequently Used),选择在之前时期使用最少的页面作为淘汰页。
时钟置换算法,又称最近未用算法(NRU,Not Recently Used),是一种性能和开销较均衡的算法。
CLOCK算法的实现方法:为每个页面设置一个访问位,再将内存中的页面都通过链接指针链接成一个循环队列。当某页被访问时,其访问位 置1。当需要淘汰一个页面时,只需检查页的访问位。如果是0,则选择该页换出;如果是1,则将其置为0,暂不换出,继续检查下一个页面。如果第一轮扫描中所有页面都是1,则将这些页面的访问位依次置0后,再进行第二轮扫描(第二轮扫描中一定会有访问位为0的页面),因此简单的CLOCK算法选择淘汰一个页面最多会经过两轮扫描。
简单的时钟置换算法,仅考虑到一个页面最近是否被访问过。事实上,如果被淘汰的页面没有被修改过,就不需要执行I/O操作写回外存。
只有被淘汰的页面被修改过时,才需要写回外存。
因此,改进型的时钟置换算法,除了考虑一个页面最近是否被访问过之外,还应考虑该页面是否被修改过。在其他条件都相同时,应优先淘汰没有被修改过的页面,避免I/O操作。
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
赞
踩
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。