在之前的《Linux内存管理》文章中,我们大致讲解了Linux内存管理的架构和映射过程。当然内存管理是一个复杂的模块。它涉及硬件和复杂软件算法的交互。在这篇文章中,我们将解释硬件原理和分页管理。CPU如何访问内存?答案很简单。通过内存管理单元(MMU),我们先来看一个非常简单的CPU访问内存的流程图:TLB:convertlookasidecache,使用它可以使虚拟地址到物理地址的转换速度大大提高。从上图我们可以清楚的知道CPU、DDR、MMU三者之间的关系。当CPU开启MMU时,所有的访问都是虚拟地址。首先通过MMU将虚拟地址转换为物理地址,然后通过总线访问内存(我们都知道内存挂在总线上)。那么MMU是如何将虚拟地址转换成物理地址的呢?当然,在上一篇文章中,是通过页表来实现的。MMU从页表中找出虚拟地址对应的物理地址是什么,然后访问物理内存。那么理解了上面的问题之后,题目的问题就解决了:什么是页表《CPU如何访问内存的?》?页表是一种特殊的数据结构,它存储了逻辑页和物理页框之间的映射关系,每个进程都有自己的页表。虚拟地址在我们看来是一个整体,其实不然,它是可以拆分的。可以分为:p(页码),可以存放页表的索引;d(offset),可以在页内进行地址偏移。我们假设页面大小为4KB,页表只有一级,即一级页表。虚拟地址的拆分是这样的:我们来看一下CPU、虚拟地址、页表和物理地址之间的关系。看下图:很简单,你应该看懂了。我们可以发现,如果使用一级页表,每个进程需要维护一个4MB的页表(我们可以算一下,如果是32位平台,地址空间大小为4GB,页面大小为4KB,而每个页表项占用4个字节,所以4GB/4KB*4=4MB)。因为每个进程都有自己的页表,在多进程的情况下,内存消耗简直惊人。所以一级页表是不合理的。有什么办法可以优化吗?答案是肯定的,就是使用多级页表可以节省内存。二级页表是对页表再次分页。又如,逻辑地址分为10位页号p1+10位页号p2+12位页偏移量。让我们看看图片。接入过程如下:
