咱们用通俗的语言聊聊这个世纪性跨时代的问题。
#页表项多大?
首先需要抛开一级二级x级页表的概念。对于32位的地址空间,规定按4K一页来管理,可以分成2^32B / 4K = 2^20 个页。
所以32位机器,页号范围是 0 ~ 2^20-1,这点毋庸置疑。
现在要建造一样东西来管理这些页号,首先想到的就是数组,那数组每个元素定义多大才能保证覆盖所有的页号呢?
最大页号2^20 - 1,十六进制 0xFFFFF,占了20位。所以数组里每个元素的大小至少可存放20位的数据,也就是 0 ~ 0xFFFFF中的任意一个。
好了,就按0xFFFFF来算吧,它占用多大?按字节来算,最多给他3B,就够用了。所以每项给它3B大小绰绰有余,但是为了整数操作,给它4B吧,这样正好一个页面存放整数个元素。当然多余的12bit也不是浪费的,留着做标志位权限位。
聊到这,给这个数组取个名吧,好了就要页表(page table)吧,里面的元素就叫页表项吧(page table entry)。
#聊聊页表
很多人看见一级二级三级四级页表就开始慌了
如一级的格式
如32位机器的二级的格式
如64位机器的三级的格式
擒贼先擒王,哪个才是代表页表?
一级中的page index代表页表,二级中的PTX代表页表,三级中的PTX代表页表。很多人一开始学这个就是从左往右看,然后被自己带到沟里了。实质上根据一级到三级的变化发展趋势,其实是从右往左看的。按照进化论最最本质的需求就是建立页表,然后发现页表的缺点才会在la地址上割出什么PTX啊,PMX啊这些玩意。
一级原始时代,page index就作为一个庞大的页表存在,整个大小4B * 2^20 = 4 MB,之前咱们聊过,页表就是个数组,数组就是一个顺序表,里面的内容是连续的,想想一下子开一个连续的4M空间给它,你乐意不。这么一大坨占用连续内存块,然且它是个整体,假设有个程序一直只访问它前面的一小块区域,那么后面的大部分区域可不可以让它呆在内存外面,用到在放进来?
二级农耕时代,有了需求就要去实现,把这个庞然大物分割一下吧,好主意,就按10bit来分,这样一个页表含有1024个页表项,大小为4K,4K放在内存中相比原始时代并不占地。现在划分了很多个页表,总归要有东西来管理吧,那就剩下的bit位来干这件事吧。有多少个页表,看剩下的bit。PDX的作用就是管理页表的,就像页表管理页表项,这样分割的零零落落的页表在PDX下连接了起来。PDX定义为10bit,代表PDX里也有1024个项,这里的每个项指向一个页表,所以页表总大小4B * 1024 * 1024 = 4MB, 还是4MB大小,但是只占用4K的连续内存空间,其余用不到的暂时就可以不放进内存了,用连续的PDX项,寻找离散的页表是个时代进步的表现。给PDX取个名,页目录项吧,就像书的目录,要找某个内容,先去找到目录,然后找到目录中给的页号,去定位到那一页,页里的某一行或几行就是我们要找的内容了。
当然有些页表像老赖一样常驻内存就不出去了,这时候就要搞个机制来清理它们了,吃老本不干活的直接请出去,干活的留下,这就涉及到快表的问题了,这边不讨论。
有人急了,听说页目录表项也是4B,不是只有1024项吗?给10bit,2B够了丫?是这样吗?肯定不是,按这个理解,1号页表起始地址为1,2号为2,1023号为1023??要知道页表里面是货真价实的页号,那页目录项肯定也是货真价实的东西,里面存的是某组页号所在的页表的开头,也就是,页目录表也存页号,页表也存页号,只不过页目录项每隔1024存一个页号,所以大小还是要根据页号来,也就是20bit = 3B,为了整存选4B, 剩下12bit做标志或权限位。所以页目录大小为4B * 1024 = 4K
实际代码中pdx是地址,*pdx存放1024间隔页号的某个页号,也就是就找到了ptx,*ptx存放含有物理地址相关的内容了
三级牛逼时代我就不说了,只不过分割了页目录表。
至于如何定位页号,就不说了。
所以,页表问题也就是著名的数组问题和数组里寻找数组问题。