漫画解说 ”内存映射“

722 阅读2分钟

图解内存映射

begin-dialog.png

begin-dialog2.png

begin-dialog3.png

begin-dialog4.png

begin-dialog5.png

begin-dialog6.png

begin-dialog7.png

虚拟内存空间与物理内存空间

virtual-memory-space.png

虚拟内存地址就好比每个班的学号,而物理内存地址就好比真实的学生。因为每个学号都对应不同的学生,所以虚拟内存地址也要映射到物理内存地址。

after-dialog1.png

after-dialog2.png

虚拟内存与物理内存的映射关系是通过 页表 来关联的,如下图:

virtual-memory-mapping1.png

页表 并不是按字节来进行映射的,而是按照 内存页 为单位进行映射,一般一个 内存页 的大小为 4KB(为什么要加一般呢,这是因为除了4KB,还有其他大小的内存页,如2MB,4MB,1GB等),页表 的每一个 页表项 都保存着物理内存页的地址。

所以,4GB 的虚拟内存空间需要 1MB 大小的页表来关联(因为 4GB / 4KB = 1MB)。也就是说,0 ~ 4095 的虚拟内存地址都是使用 页表 的第一个 页表项 来映射的,而 4096 ~ 8191 的虚拟内存地址使用 页表 的第二个 页表项 来映射的,以此类推...

那么,通过什么样的算法能把 0 ~ 4095 的虚拟内存地址转换为页表的第一个页表项呢?其实很简单,只需要把虚拟内存地址的高端 20 位作为页表的索引,而把低端 12 位作为内存页中的偏移量即可,如下图:

virtual-memory-mapping2.png

在上图中,还看到了一个 cr3 的东西,这是 CPU 中的一个寄存器,用于保存 页表 的物理内存地址,通过这个寄存器就能找到进程的 页表 了。

现在对内存映射的原理有了比较清晰的了解了,但现在有个问题,每个进程都要 1MB 大小的页表,那不是很浪费内存吗?的确是,因为进程很多虚拟内存地址并不会用到,为了节省页表使用的内存,x86 CPU 把页表分为 2 级,如下图:

virtual-memory-mapping3.png

如上图所示,把原来的 页表 划分为 页目录页表,它们的大小均为 4KB。而虚拟内存地址的高 10 位作为页目录的索引,而中间 10 位作为页表的索引,低 12 位还是作为物理内存页的偏移量。

把原来的 页表 划分为两级后,进程有些不使用的虚拟内存地址就不需要进行映射,从而节省了内存的使用。