图解|什么是缺页错误Page Fault

3. 内存的惰性分配

以32位的Linux系统为例,每个进程独立拥有4GB的虚拟地址空间,根据局部性原理没有必要也不可能为每个进程分配4GB的物理地址空间。

64位系统也是一样的道理,只不过空间寻址范围大了很多很多倍,进程的虚拟地址空间会分为几个部分:

实际上只有程序运行时用到了才去内存中寻找虚拟地址 对应 的页帧,找不到才可能进行分配,这就是 内存的惰性(延时)分配机制

对于一个运行中的进程来说,不是所有的虚拟地址在物理内存中都有对应的页,如图展示了部分虚拟地址存在对应物理页的情况:

虚拟地址空间根据固定大小一般是4KB进行划分,物理内存可以设置不同的页面大小,通常物理页大小和虚拟页大小是一样的,本文按照物理页4KB大小展开。

经过前面的分析,我们 将面临一个问题: 如何将虚拟地址准确快速地映射到物理页呢

>>>高能预警 敲黑板 本段小结<<<

1.Linux的虚拟地址空间就是 空头支票 ,看着很大但是实际对应的物理空间只有很少的一部分。

2.内存的 惰性分配 是个有效的机制,可以保证内存利用率和服务器利用率,是资源合理配置的方法。

3.大量的虚拟地址到物理地址的 快速准确地查询转换 是一个难题。

4. CPU如果获取内存中的数据

CPU并不直接和物理内存打交道,而是把地址转换的活外包给了MMU ,MMU是一种硬件电路,其速度很快,主要工作是 进行内存管理,地址转换只是它承接的业务之一

一起看看MMU是如何搞定地址转换的。

4.1 MMU和Page Table

每个进程都会有自己的页表Page Table,页表存储了进程中虚拟地址到物理地址的映射关系,所以就相当于一张地图,MMU收到CPU的虚拟地址之后开始查询页表,确定 是否存在映射以及读写权限是否正常 ,如图:

对于4GB的虚拟地址且大小为4KB页,一级页表将有2^20个表项,页表占有连续内存并且存储空间大,多级页表可以有效降低页表的存储空间以及内存连续性要求,但是 多级页表同时也带来了查询效率问题

我们以2级页表为例,MMU要先进行两次页表查询确定物理地址,在确认了权限等问题后,MMU再将这个物理地址发送到总线,内存收到之后开始读取对应地址的数据并返回。

MMU在2级页表的情况下进行了2次检索和1次读写,那么当页表变为N级时,就变成了N次检索+1次读写。

可见, 页表级数越多查询的步骤越多,对于CPU来说等待时间越长 ,效率越低, 这个问题还需要优化才行。

>> 本段小结 敲黑板 划重点 <<

1.页表存在于进程的内存之中,MMU收到虚拟地址之后查询Page Table来获取物理地址。

2.单级页表对连续内存要求高,于是引入了多级页表,但是 多级页表也是一把双刃剑 ,在减少连续存储要求且减少存储空间的同时降低了查询效率。

4.2 MMU和TLB的故事

MMU和TLB的故事就这样开始了…

CPU觉得MMU干活虽然卖力气,但是效率有点低,不太想继续外包给它了,这一下子把MMU急坏了。

MMU于是找来了一些精通统计的朋友,经过一番研究之后发现CPU用的数据经常是一小搓,但是每次MMU都还要重复之前的步骤来检索,害,就知道埋头干活了,也得讲究方式方法呀!

找到瓶颈之后, MMU引入了新武器,江湖人称快表的TLB ,别看TLB容量小,但是正式上岗之后干活还真是不含糊。

当CPU给MMU传新虚拟地址之后,MMU先去问TLB那边有没有,如果有就直接拿到物理地址发到总线给内存,齐活。

TLB容量比较小,难免发生Cache Miss ,这时候MMU还有保底的老武器页表 Page Table,在页表中找到之后MMU除了把地址发到总线传给内存,还把这条映射关系给到TLB,让它记录一下刷新缓存。

TLB容量不满的时候就直接把新记录存储了,当满了的时候就开启了淘汰大法把旧记录清除掉,来保存新记录,彷佛完美解决了问题。

在TLB和Page Table加持之下,CPU感觉最近MMU比较给力了,就问MMU怎么做到的?MMU就一五一十告诉了CPU。

CPU说是个不错的路子,随后说出了自己的建议: TLB还是有点小,缓存不命中也是经常发生的,要不要搞个大的,这样存储更多访问更快

MMU一脸苦笑说道大哥 TLB很贵的 ,要不你给涨点外包费?话音未落,CPU就说涨工资是不可能了,这辈子都不可能了。