分页内存管理方案允许进程的物理地址空间是不连续分配的。分页避免了将不同大小的内存块备份到交换空间上的问题。分页可以说是工程实践中的一种伟大创造。分页是通过硬件和操作系统配合来实现的。
我们将物理内存分为大小固定得块,称为帧(frame);将逻辑内存也分为同样大小的块,称为页(page)。分页需要硬件支持。CPU将所生成的地址分为两个部分,页码和偏移。页码作为页表中的索引。页表包含每页所在物理内存的基地址。基地址和偏移量组合起来就形成了物理地址。
页的大小通常是2的幂。选择2的幂可以很便捷的将逻辑地址转换为页码和页偏移。如果逻辑地址空间为
,并且页大小为
。那么逻辑地址的高m-n位表示页码,而低n位表示页偏移。如下所示。
页码 | 页偏移 |
---|---|
p | d |
实际物理内存等于:页码*页大小+页偏移。
采用分页技术不会产生外部碎片,但是会产生内部碎片。因为进程要求的内存可能不是页的整数倍,但是系统分配的时候一定是按照帧为单位来分配。需要合理设置页的大小。页设置的过小,将会导致页表增大,页设置的过大,可能导致内部碎片变大。现在的页,一般都是4KB或者8KB大小的。有的CPU支持多种分页大小。
页表中每一个条目通常为4B,不过这是可以改变的。分页的一个重要特点是用户观点的内存和实际物理内存的分离。用户程序将内存作为一整块来处理,而且只包含一个进程。实际上却是,物理内存中存在多个进程。
在分页的情况下,一个进程是不可能访问到别的进程的内存。唯一的问题在于需要验证是否对只读的页进行了写操作。
这个问题可以通过可以通过检测保护来验证。也可以通过硬件实现。
在页表中,还有一个位通常与页表中的每一条目关联:有效-无效位。当该位有效的时候,表示相关的页在进程逻辑地址空间,因此是有效的页。该位无效的时,该值表示相关的页不再进程逻辑内存空间。
现在是一个64位计算机的时代,计算机在理论上支持2^64B大小的内存。但是实际上不会有这么大的,2^64=18446744073709551616。这个数值太过恐怖。个人PC的地址总线基本在35位左右。不会比这个更大了。当内存越来越大,页表大小仍旧是4KB的时候,那么页表就会变得非常大。就算是4GB内存,每页4KB,那也会有2^32/2^12这么多条目。一个页表高大100万的条目。每个条目通常4B,那么页表的大小就达到惊人的4MB。
为了解决页表过大的问题,提出了两层分页算法。即页表在分页。两层分页算法在32位计算机的时候,看起来还是不错的。但是在64位计算机的时代,这个方案也不行。只好将分页的层数加多。
分页的另一个优点是可以共享代码。这对于可重入代码而言是非常重要的,每个进程只需要有自己的数据页即可。代码共享。可重入代码是不能自我改变的代码。