目录
在解决大多数空间管理问题上面,操作系统有两种方法:
第一种就是将空间分割成不同长度的分片,类似于虚拟内存管理中的分段,但是这个方法存在一个问题,就是当长时间之后,因为碎片化的空间,导致后面的分配会存在问题。
第二种方法:将空间分割成固定大小的分片,这被称为分页。因为是固定大小,所以也就解决了上面存在的问题,每个分片被称为一页,同样,在物理内存中,奖定长槽块的阵列,叫做页帧。
简单例子
在这里首先划分出64字节的虚拟空间,然后再有128字节的物理空间地址,可以看出,在物理空间中有一部分是给操作系统保留的,通过分页的方法,可以分成大小相同的页,然后在获取或者是保存的时候,可以随机拿出来,不需要有特定的顺序,所以大大的提高了灵活性。
然后为了方便记录地址空间的每个虚拟页在物理内存中的位置,每个进程都有一个数据结构,被称为页表,这个页表可以用来虚拟页到地址之间的转换。
接下来通过完成一个地址转换的例子,说明整个流程。
因为是64字节,所以虚拟地址需要6位(2^6=64)。Va5 是虚拟地址的最高位,Va0 是最低位。因为我们知道页的大小(16 字节),
所以可以进一步划分虚拟地址
每个页的大小是16字节,在64字节中一共有4个页,那前两位的虚拟页号就是用来判断的,后面的偏移量是用来确定该页的哪个字节。
假设加载的虚拟地址是21,二进制也就是010101
01也就是页号,后面的就是字节处。然后检索页表,找到虚拟页1所在的物理页面,然后进行替换,将这个地址发送给物理内存,获取数据。这里的偏移量是不需要发生改变的。
页表存在哪里
在实际中,以经典的32位为例,是4KB的页,虚拟内存被分为20位的VPN和12位的偏移量。那也就是为每个进程管理2^20个地址转换,如果每个页表格条目需要4字节来保存信息,那算下来每个页表就是要4MB,这个是比较大,如果是100个进程,那你就无法想象你的机器是怎样的。
所以将每个进程的页表存储在内存中(在后面会更加详细)
列表中究竟有什么
页表的结构,页表就是将虚拟地址(或者实际上,是虚拟页号)映射到物理地址(物理帧号)。任何的数据结构都是可以采用的,最简单的就是数组,将两个号一一对应,然后通过所以查找页表项(PTE),后面会介绍到高级的结构。
对于每个PTE有什么位,是需要了解的
-
有效位:通常用于指示特定地址转换是否有效。在进程中,由于中间空间是没有被使用的,所以标记为无效。如果访问的话,会陷入操作系统。
-
保护位:表明页是否可以读取、写入或执行。
-
存在位:表示该页是在物理存储器还是在磁盘上(即它已被换出,swapped out)。
-
参考位(访问位):用于追踪页是否被访问,也用于确定哪些页很受欢迎,因此应该保留在内存中。
分页:也很慢
在上面中了解了页表,那接下来就具体看一下怎么获取数据,如果执行:movl 21, %eax
想要获取数据,系统首先要将虚拟地址转化的物理地址。所以,在获取数据前,系统要在进程的页表中拿到页表项没然后进行转换,最后在加载数据。
要运行这个过程,那硬件必须知道运行的进程的页表的位置。假设一个页表基址寄存器(page-table base register)包含页表的起始位置的物理地址。
那怎么操作呢?比如是:0x30,(二进制11000),为了拿到VPN,右移4位,得到4。假如虚拟地址是21(二进制010101),将其转化为010000,然后移位变成01,,然后在使用这个值作为页表机制寄存器指向PTE数组的索引。
那接下来就可以利用页表项获取物理帧号了,最后和偏移量结合,形成物理地址。
最后就可以拿到数据,放入到寄存器里面。这里面整个过程是比较复杂的。所以有时候运行起来也是比较慢的。
内存追踪
书中讲的很复杂,也就是为了体现出整个内存管理的复杂性,在后面可以使用mmap的底层原理来讲解这些知识。
小结
在这里首先讲了分页的知识,理解了为什么使用分页,之前的分段技术存在什么问题。在后面了解了分页的一些基础性原理。知道了需要有强大的机器去支持这个机制, 如果不小心考虑的话,分页会导致较慢的机器(有许多额外的内存访问来访问页表)和内存浪费(内存被页表塞满而不是有用的应用程序数据)