很久以前就想写一下关于虚拟内存管理方面的文章,主要还是写给自己看的。原因主要是自己对Linux虚拟内存管理也是一知半解,写一篇博客,记录一下自己这几天的学习笔记,留着以后做参考。
这一篇主要讲一下虚拟地址到物理地址的转换。主要参考《深入理解计算机系统》一书。
关于逻辑地址、线性地址和物理地址
物理地址:
物理地址可以想象成实际物理存储上的地址
线性地址:
线性地址也可以叫做虚拟地址,是一个不真实的地址,可以理解为页式管理中的地址
逻辑地址:
逻辑地址与线性地址一样,是一个不真实的地址,用于Intel段式管理中的地址
三个地址的转换关系:
逻辑地址–>线性地址–>物理地址
逻辑地址–>线性地址
逻辑地址由两部分组成,段标识符和段内偏移地址。段标识符是有个16位长的字段组成,叫做段选择符。其中高13位是一个索引号,如下图:
索引号用于索引段描述符表的某一段描述符,段描述符格式如下图:
在Linux下,段描述符的Base都是0,因此逻辑地址的段内偏移量就是线性地址,接下来看一下线性地址怎样转换成物理地址的。
线性地址–>物理地址
首先宏观上的看一下线性地址(虚拟地址)到物理地址的转换
虚拟地址高位有一个页表索引,通过页表索引可以在页表中找到对应的一个页表入口(Page Table Entry),在PTE中可以得到物理页号,然后在加上原先在虚拟地址中的偏移量,就会定位到最终的地址。
基本流程
如上图是一个正常的命中流程:
- 处理器生成一个虚拟地址,并将其给MMU
- MMU生成一个PTE地址,从高速缓存/主存中请求获取
- 高速缓存/主存将PTE数据传回MMU
- MMU生成物理地址,传给高速缓存/主存
- 高速缓存/主存将数据传回处理器
上图是发生缺页中断的情况,高速缓存/主存会将牺牲页换出,将新页换进。
利用TLB加速地址翻译
TLB全称翻译后备缓冲器(Translation Lookaside Buffer),位于MMU内存,其实就是缓存住了一些PTE,那么MMU就不需要从高速缓存/主存中获取PTE了。
多级页表
如果是32位的虚拟地址空间,一个页的大小为4K,那一张页表就有1M个PTE,如果每个PTE的大小为4个字节,那么页表占用内存大小为4MB。如果是64位机器,它的寻址位数是48位,那页表就更大了。
解决方式是讲页表分为多级,如下图:
地址翻译的过程基本就差不多了。