操纵系统之内存管理--非连续分配方式
一.基本分页存储管理
引言:固定分区会产生内部碎片,动态分区会产生外部碎片,这两种分配方式对内存的利用率较低,
因而引入分页存储的思想:将内存空间分为相等大小的块,每一块即是一页,每一页比较小,系统将进程划分为若干块(若干页),每一页分别去申请内存块。
内部碎片:固定分区中,若一个进程比较小,而为其分配的内存比较大,剩余的内存空间无法利用,这就是内部碎片。
外部碎片:动态分区中,若一个进程因内存空间中,有含有较小的内存区间而无法为其分配出去 ,这就产生了外部碎片。
1.分页存储的几个基本概念
(1)页面,页面大小:页面是指进程中的块,内存中的块称为页框,页面大小为2的整数次幂倍,页面大小根据地址结构中的偏移量决定。
(2)地址结构:逻辑地址中分为:页号P与页类偏移量。比如32位的逻辑地址,0-11位为页类偏移量,12-31位为页号,这就说明,一个页面大小为2的11次方=4KB,而页的数量最多可以为2的20次方页
(3)页表:一个进程对应一个页表,页表的作用是用于存储页号所对应的物理块号,页表由两部分组成,页号+物理块号,每一个页号对应一个物理块号,页号不占存储空间。
比如:当进程需要访问内存中的某个数据时,就根据逻辑地址计算出页号,找到页表中所对应的物理块号,然后将物理块号与逻辑地址中的页类偏移量相加就得到了实际物理地址。
(这里物理块号+页内偏移量,若是二进制则直接拼接,十进制就是数学上的相加)
(4)页表项大小:32位的逻辑空间地址,每页大小为4KB,最多有2的20次方个页面,要使用页表表示这么多的页面,则需要20位才能容纳所有页面,大约需要3B的存储空间,若使用4B大小的的存储空间
4B=4*8=32位,系统按照字节编址,假如一个块的大小为一个字节(1B=8位,2的8次方个地址,32位为2的32次方个地址),一个页面的大小为4KB,则一页可以装下1K个页表项。(这里第一次看我是比较难以理解,想了半天,涉及到计算机组成原理中的地址空间与存储空间)
举个列子:前提条件,系统按照字节编址,32位逻辑地址,页面大小为4KB。
- 有一个酒店(内存),去住酒店的时候会给你自动分配一个房间(申请内存),酒店的每一层楼的房间数量一样,一个房间代表一个内存块,则每一层的房间数量为4KB,即是页面大小(2的12次方个房间),既然是酒店,每个房间肯定都有门牌号,这样去住酒店的时候,才知道自己住的房间在哪里,如果没有门牌号,那么房间是否是有人在住都不知道。这里的门牌号就是每个房间的物理地址。既然是32位的逻辑地址,则最多总共可以表示2的32次方个房间,每一层有2的12次方个房间(即每一页大小为4KB),则酒店有2的20次方层(页的数量)。假如楼页号即楼号从0开始,0,1,2····一直到2的20次方层,那么每个房间的门牌号由两部分组成:前20位层号(物理块号)+后12位房间号(页类偏移量),这样不同层楼都都会有相同的房间号,但是相同的房间号门牌号绝对不同,找房间按照门牌号来找。门牌号是物理地址,我怎样才能找到对应的房间是哪里呢?假如每一层楼都有一个管理员(页表项),那么我最多需要2的20次方个管理员才能管理下整个酒店,每个管理员手中都有一把钥匙,每一把钥匙只能打开一个房间,每个管理员可以拿到整个酒店每个房间的钥匙,但是一次性只能拿一把钥匙(一个页号对应一个物理块号)。现在对管理员进行编号,每个管理员都有一个工号,那我怎么样编号才合适呢?总共有2的20次方个管理员,那么我至少需要20位二进制(大约3B)才能把每个管理员编号完成,那么我使用32位二进制(4B地址空间大小)完全够了。现在问题来了,我们知道在二进制中0和1代表两种不同的状态,1个房间大小是1B即有8位二进制数,可以表示2的8次方种状态,我有2的32次方个人,那么我需要32个二进制位才能表示这么多不同的人(每个人都不一样),工号的位数代表管理员要占用的房间有多大,32位的工号,就要使用32/8=4(即4B存储空间)个房间来让管理员住,一个人要消耗四个房间大小的空间。即4B大小的页表项,那么一层楼房间数量是4KB就可以装下1K个页表项,可以住1024个管理员,2的20次方个管理员需要2的20次方*4B=4MB空间大小,总共需要4MB/4KB=1024层楼来住管理员。页表项大小就是指的是页表的地址空间(工号)所占用的存储空间(房间数量)。现在召开管理员大会,所有管理员集中在一个广场上,那么这个管理员的集合体就是页表。
- 操作系统中处理器的物理寻址能力决定了虚拟内存的大小。假如单核处理器的地址总线是32位,寻址能力是32位,则可以找到内存为2的32次方=4GB大小的内存空间,再大就找不到了。页表是存储在内存中的,为什么表页表项的地址需要占用存储空间呢?为什么物理地址就不占用存储空间呢?因为物理地址应该是在CPU地址寄存器中,不在内存中,而页表实在页表寄存其中,是在内存中。
页目录表
2.基本地址变换机构
地址变换机构是将逻辑地址转换为物理地址,系统中会有一个页表寄存器。
二进制逻辑地址到物理地址的转换:物理地址=物理块号+偏移量。
十进制计算:1.计算页号P=A/L(A逻辑地址,L是页面大小)和页类偏移量W=A%L
2.比较页号与页表长度M,若P>=M,则地址不合法,中断处理。
3.若地址合法,页表项地址=页表起始地址+页号P*页表项长度,去除物理块号b
4.物理地址=b*L+W
3.具有块表的地址变换机构
地址转换应该足够块,否则访问速度会降低,页表不能太大,否则内存利用率会降低。
高速缓冲存储器--块表,也称相联存储器(TLB)。因此主内存中的页表也称慢表。
1.CPU给出逻辑地址后,由硬件进行地址转换,将页号送如高速缓冲器中,并将页号与块表中的所有页号进行匹配。
2.若找到匹配的页号,则取出块表中页号所对应的物理块号,然后与偏移量直接拼接形成物理地址。
3.若未找到匹配的页号,则需要访问主存中的慢表,然后与偏移量拼接形成物理地址,接着将页表项存入块表中。
4.两级页表
- 页表的页表,再加一级页表。
- 32位逻辑地址,页面大小为4KB,页表项大小为4B。若要实现进程对全部逻辑地址空间的映射,则进程就需要2的20次方个页表项,大约100万个(管理员)
- 以一个40MB的进程为例,总共有40MB/4KB*4B=40KB的页表项,则需要10个页框来保存页表。整个进程大约有1W个页面,若要求10个页面大小的页表必须全部加载进内存,但运行时只需要几十个页面,因而大大降低的内存利用率,所以需要二级页表,为这10个页表建立上一级页表(顶级页表,只能有一个页面来存储顶级页表的地址),执行的时候只需要将顶级页表调入内存即可,进程的页表与进程本身可以后面运行的时候调入。
- 上面知道,32位的逻辑地址,4KB的页面大小,则偏移量有12位,采用分级,页表项大小为4B(地址空间),则一个页面可以容纳4KB/4B=1K个页表项,1K个页表项可以用10位二进制来表示,则32位逻辑地址就由一级页号(顶级页号10位)+二级页号(10位)+偏移量(12位)组成两级页表的逻辑地址。
- 举个列子方便理解:上面酒店的列子说到,管理员需要使用4个房间,即4B。我要去找一个人,先找到对应的管理员,管理员再带我去找到相应的房间,2的20次方的管理员找起来不是一般的麻烦,所引出管理员中的管理员,即超级管理员(顶级页表页表项)。所以要对超级管理员进行另外的编号,超级管理员的编号为4KB/4B=1K(1024)个超级管理员(页表大小为4KB,每个页表项大小是4B),每个人所占用房间数量为4间,即4B。先根据逻辑地址先找到顶级页号,接着取出对应的物理块号+偏移量到下一级页表所存储的物理块(内存块),取出内存块中的二级页表数据,再根据二级页号在二级页表数据中找到对应的物理块号,最后再根据物理块号拼接上偏移量得到最终的物理地址。上面列子中超级管理员个数*管理员个数=2的10次方*2的10次方=2的20次方,恰好为楼层数(就是未分层前的页号),所以得到每个超级管理员要管理2的10次方个管理员,那么管理员的个数最多为2的20次方个不变。
二.基本分段存储管理
1.分段
- 分页管理方式是从计算机的角度考虑的,目的是提高内存的利用率,对用户透明。段式管理方式是按照用户进程中的自然段划分的逻辑空间,对用户是透明的。
- 段类是要求连续的地址空间,段间不要求连续。
- 32位的逻辑地址,16位段号,16位段内偏移量。段号2的16次方表示最大可以分为2的16次方个段,每一段最大长度也就是段长为2的16方/8B=64KB.
2.段表
- 每个进程都有一张逻辑空间与内存空间映射的段表。段表由3部分组成=段号+段长+本段在住内存地址。段号不占存储空间
- 段表与页表类似。
3.地址变换机构
- 段表寄存器=段表始地址+段表长度,逻辑地址映射到物理地址过程如下:
- 通过逻辑地址得到段号与段内偏移量。段号S与与段表寄存器中的段表长度M比较,S>=M则产生越界中断。段号S对应的段表项地址=段表始地址F+段号S*段表项长度,取出段表项的前几位得到段长C,然后与段类偏移量比较,若>=C,则产生越界中断。最后取出段表项中的地址b,将地址b与段内偏移量拼接得到最终物理地址。
4.段的共享与保护
- 不能修改的代码与数据可以共享,可以修改的代码与数据不能共享。分段管理地址空间是二维的,页式管理地址空间是一维的。
三.段页式管理方式
- 先分段,后分页,先分成段,在为每一段分成页。页式存储管理提高内存利用率,段式管理反映程序的逻辑结构并且有利于共享。
- 逻辑地址=段号S+页号P+页类偏移量(由系统自主划分)
- 在一个进程中,段表只有一个,而页表可能有多个。
- 进行一次访问实际上要访问3次主内存。