分页系统的地址变换机构

首先,我们得理清分页的概念;

在计算中,存储的最小的单位是位(bit),其值要么是0,要么是1。而单纯的0或1所能表示的信息极为有限,所以,在计算机中,我们以最小一个字节(Byte,字)为基本单位来进行操作,存储我们的数据。(注释:对于布尔类型,值为1或0,理论上只占一位,但在计算机中,实际操作时一般是占用一个字节的空间,当然,在具体实现中也可能多于一个字节。)

操作系统对每一个字节进行了编号,比如从0000 0000开始,然后是0000 0001,再然后是0000 0002,0000 0003 、、、

内存示意图

根据不同的系统,不同的内存大小,所用来进行地址计数的数的位数有所差别,但道理不变;

然后,为了解决在操作中面临的一些问题,我们想出了分页的办法,什么是分页呢?就是原本是以一个字节为最小单位去存取数据,这样地址实在是太多了,每次一个一个的去找,实在是很麻烦,而且,我们经常会使用一段连续的空间。

有没有什么办法可以不这么麻烦呢 ?有的,就是分页。

我们将连续的一定数量的字节(通常一页大小为1KB~8KB)视为一个整体(逻辑上),即为一页,然后对进行编号,比如从0000 0000开始,然后是0000 0001,再然后是0000 0002,0000 0003 、、、

举例:计算机内存物理地址编码为0000 0000 0000 0000 ~ 1111 1111 1111 1111,(计算机内存地址以二进制来计数,我们在C语言中看到的16位地址,实际上是逻辑地址,是面向用户的,并非实际进行操作时的最底层物理地址)

如果我们把连续的2KB(2^{11} Byte)视为一页,那么内存可以被分为2^{16} ÷ 2^{11}  =  2^{5} 块(在逻辑地址中,我们称为页,在实际物理地址中,称为块。本质是操作系统同时和用户程序和实际物理地址打交道,对于用户程序,我们约定为页;对于实际物理地址,操作系统将同样大小的内存空间视为块),然后操作系统对块进行编号,从 0000 0 到 1111 1;(这是操作系统和我们的约定,最底层的物理内存可不知道我们把它们看成了一块一块的)

对内存以2KB分页,同一种颜色的为一页,并编号

然后,我们需要使用内存的时候,就去和操作系统打交道,告诉它我们需要多少内存,然后操作系统根据内存使用情况,判别还有哪些块是空的,然后分配给我们需要的大小的块数,分页的优点在这个步骤就体现出来了,可以不用一定分配连续的内存空间给用户程序,而是分配 页 给用户程序,可以是不连续的。可是,页可以是不连续的,那我们怎么知道我们被分到了哪些页呢?嗯,所以操作系统在分配内存时要建立一个表,表中记录你是哪个程序,分配给了你哪些页。

在用户程序的运行过程中,各种操作都是给出逻辑上的操作,然后,交给操作系统去实现。

比如:

我们在上面的假设的基础上,现在一个程序向操作系统申请10KB(即5页)的空间,操作系统就会根据目前的内存使用情况,进行分配。假设内存现在够用, 操作系统分给程序5页的内存空间的使用权限,程序就会知道自己有5页的内存空间可用,编号为 0 - 4,即 000 ~ 100。但是,这5页在程序看来是连续的,在操作系统这里,其实不一定是连续的,可能是下图的情况:


如果用户程序想访问逻辑地址为 0001 1101 1011 1010 的内存,需要由操作系统进行转换,操作系统得到实际的物理地址后,告诉用户程序,诺,这就是你要访问的内存,然后程序在上面操作,下面讲解具体的过程。

当用户提出内存访问请求时,分页地址变换机构会将所提交访问的逻辑地址转换为实际物理地址

首先,将逻辑地址拆分为两部分,页号 + 页内地址  比如:

逻辑地址为0001 1101 1011 1010 的内存地址,根据前面的条件,页号是 5 位,即:

页号: 0001 1  +  页内偏移: 101 1011 1010

然后去找到页表,去其中找到与页号对于的物理块,在找之前,要根据页号,判断一波,看页号是不是越界了,比如,在这里页号是 0001 1 =》 3 ,没有超过操作系统分配给程序的页的上限5,所以没有越界,如果越界了,操作系统会产生越界中断。

在这里,有个问题需要解决,页表在哪里呢?在上面我们知道那个对应关系(页=》块)是由操作系统维持的,操作系统把它放在哪里的呢?

由于逻辑地址到物理地址的转换是很频繁的操作,所以考虑用寄存器来存放页表,这样可以大大提高速度,但通常页表很大,如果全部放在寄存器里,那成本就太高了,所以,退一步,我们把页表存放在内存里。这里需要回顾一下,内存是由一个个字节递增的地址表示的,我们前面讨论的都是内存的管理与分配问题。我们前面的问题都还没有解决,那我们把页表放在内存里,怎么放呢?它需要用到页表吗?那不成了它依赖自己的死循环了?嗯,实际是存放页表时不需要依赖页表,操作系统把页表存在内存中一段连续的空间,然后有个起始地址(这个是真实的物理地址),还有个页表长度(即页表有多大,占用了多少空间),然后,操作系统把这两个信息放到一个寄存器里。

操作系统需要用到页表的时候,就去寄存器处取得页表相关信息(首地址+页表大小)。

那我们是怎样去从页表获得物理块的呢?

首先,将页表在内存中的开始地址作为起始地址(图中红色线的地址):

加上表项的增量,(即  页号  ×  每个表项所占的内存大小),便来到了存放有该页号在页表中对应的表项的位置(图中绿色线的位置)。取出其中的内容(页号+对应的块号),便可获得实际的物理块号;仅仅得到物理块是不够的,还得知道在物理块中的什么位置,因为具体操作的时候,操作系统还是以字节为基本单位进行操作的。回到所请求的地址(逻辑地址),我们利用了前面一部分,还有后面一部分。现在我们来将它利用起来,把它直接作为物理地址的后一部分就可以了。获得了实际的物理块,我们加上页内偏移(逻辑地址的后一部分),即可获得物理地址,所以物理地址是:

3 + 101 1011 1010  =》  1011 0 + 101 1011 1010  =》 1011 0101 1011 1010

于是,一个用户程序逻辑地址就被操作系统转换为了实际物理地址。

总结:

操作系统需要借助页表来管理、分配内存,而页表本身就是存放在内存空间中一段连续的空间中的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容