CPU是如何访问内存的?

内存管理可以说是一个比较难学的模块 , 之所以比较难学 。一是内存管理涉及到硬件的实现原理和软件的复杂算法 , 二是网上关于内存管理的解释有太多错误的解释 。希望可以做个内存管理的系列 , 从硬件实现到底层内存分配算法 , 再从内核分配算法到应用程序内存划分 , 一直到内存和硬盘如何交互等 , 彻底理解内存管理的整个脉络框架 。本节主要讲解硬件原理和分页管理 。
 
CPU通过MMU访问内存我们先来看一张图:

CPU是如何访问内存的?

文章插图
从图中可以清晰地看出 , CPU、MMU、DDR 这三部分在硬件上是如何分布的 。首先 CPU 在访问内存的时候都需要通过 MMU 把虚拟地址转化为物理地址 , 然后通过总线访问内存 。MMU 开启后 CPU 看到的所有地址都是虚拟地址 , CPU 把这个虚拟地址发给 MMU 后 , MMU 会通过页表在页表里查出这个虚拟地址对应的物理地址是什么 , 从而去访问外面的 DDR(内存条) 。
所以搞懂了 MMU 如何把虚拟地址转化为物理地址也就明白了 CPU 是如何通过 MMU 来访问内存的 。
MMU 是通过页表把虚拟地址转换成物理地址 , 页表是一种特殊的数据结构 , 放在系统空间的页表区存放逻辑页与物理页帧的对应关系 , 每一个进程都有一个自己的页表 。
CPU 访问的虚拟地址可以分为:p(页号) , 用来作为页表的索引;d(页偏移) , 该页内的地址偏移 。现在我们假设每一页的大小是 4KB , 而且页表只有一级 , 那么页表长成下面这个样子(页表的每一行是32个 bit , 前20 bit 表示页号 p , 后面12 bit 表示页偏移 d):
CPU是如何访问内存的?

文章插图
CPU , 虚拟地址 , 页表和物理地址的关系如下图:
CPU是如何访问内存的?

文章插图
【CPU是如何访问内存的?】页表包含每页所在物理内存的基地址 , 这些基地址与页偏移的组合形成物理地址 , 就可送交物理单元 。
上面我们发现 , 如果采用一级页表的话 , 每个进程都需要1个4MB的页表(假如虚拟地址空间为32位(即4GB)、每个页面映射4KB以及每条页表项占4B , 则进程需要1M个页表项(4GB / 4KB = 1M) , 即页表(每个进程都有一个页表)占用4MB(1M * 4B = 4MB)的内存空间) 。然而对于大多数程序来说 , 其使用到的空间远未达到4GB , 何必去映射不可能用到的空间呢?也就是说 , 一级页表覆盖了整个4GB虚拟地址空间 , 但如果某个一级页表的页表项没有被用到 , 也就不需要创建这个页表项对应的二级页表了 , 即可以在需要时才创建二级页表 。做个简单的计算 , 假设只有20%的一级页表项被用到了 , 那么页表占用的内存空间就只有0.804MB(1K * 4B + 0.2 * 1K * 1K * 4B = 0.804MB) 。除了在需要的时候创建二级页表外 , 还可以通过将此页面从磁盘调入到内存 , 只有一级页表在内存中 , 二级页表仅有一个在内存中 , 其余全在磁盘中(虽然这样效率非常低) , 则此时页表占用了8KB(1K * 4B + 1 * 1K * 4B = 8KB) , 对比上一步的0.804MB , 占用空间又缩小了好多倍!总而言之 , 采用多级页表可以节省内存 。
二级页表就是将页表再分页 。仍以之前的32位系统为例 , 一个逻辑地址被分为20位的页码和12位的页偏移d 。因为要对页表进行再分页 , 该页号可分为10位的页码p1和10位的页偏移p2 。其中p1用来访问外部页表的索引 , 而p2是是外部页表的页偏移 。
CPU是如何访问内存的?

文章插图

CPU是如何访问内存的?

文章插图
 



    推荐阅读