大页内存(HugePages)原理

3. 原理

大页内存的原理涉及到操作系统的虚拟地址到物理地址的转换过程。操作系统为了能同时运行多个进程,会为每个进程提供一个虚拟的进程空间,在32位操作系统上,进程空间大小为4G,64位系统为2^64(实际可能小于这个值)。在很长一段时间内,我对此都非常疑惑,这样不就会导致多个进程访存的冲突吗,比如,两个进程都访问地址0x00000010的时候。事实上,每个进程的进程空间都是虚拟的,这和物理地址还不一样。两个进行访问相同的虚拟地址,但是转换到物理地址之后是不同的。这个转换就通过页表来实现,涉及的知识是操作系统的分页存储管理。

分页存储管理将进程的虚拟地址空间,分成若干个页,并为各页加以编号。相应地,物理内存空间也分成若干个块,同样加以编号。页和块的大小相同。假设每一页的大小是4K,则32位系统中分页地址结构为:

为了保证进程能在内存中找到虚拟页对应的实际物理块,需要为每个进程维护一个映像表,即页表。页表记录了每一个虚拟页在内存中对应的物理块号,如图三。在配置好了页表后,进程执行时,通过查找该表,即可找到每页在内存中的物理块号。

在操作系统中设置有一个页表寄存器,其中存放了页表在内存的始址和页表的长度。进程未执行时,页表的始址和页表长度放在本进程的PCB中;当调度程序调度该进程时,才将这两个数据装入页表寄存器。

当进程要访问某个虚拟地址中的数据时,分页地址变换机构会自动地将有效地址(相对地址)分为页号和页内地址两部分,再以页号为索引去检索页表,查找操作由硬件执行。若给定的页号没有超出页表长度,则将页表始址与页号和页表项长度的乘积相加,得到该表项在页表中的位置,于是可以从中得到该页的物理块地址,将之装入物理地址寄存器中。与此同时,再将有效地址寄存器中的页内地址送入物理地址寄存器的块内地址字段中。这样便完成了从虚拟地址到物理地址的变换。

由于页表是存放在内存中的,这使CPU在每存取一个数据时,都要两次访问内存。第一次时访问内存中的页表,从中找到指定页的物理块号,再将块号与页内偏移拼接,以形成物理地址。第二次访问内存时,才是从第一次所得地址中获得所需数据。因此,采用这种方式将使计算机的处理速度降低近1/2。

为了提高地址变换速度,可在地址变换机构中,增设一个具有并行查找能力的特殊高速缓存,也即快表(TLB),用以存放当前访问的那些页表项。具有快表的地址变换机构如图四所示。由于成本的关系,快表不可能做得很大,通常只存放16~512个页表项。

上述地址变换机构对中小程序来说运行非常好,快表的命中率非常高,所以不会带来多少性能损失,但是当程序耗费的内存很大,而且快表命中率不高时,那么问题来了。

4. 小页的困境

       现代的计算机系统,都支持非常大的虚拟地址空间(2^32~2^64)。在这样的环境下,页表就变得非常庞大。例如,假设页大小为4K,对占用40G内存的程序来说,页表大小为10M,而且还要求空间是连续的。为了解决空间连续问题,可以引入二级或者三级页表。但是这更加影响性能,因为如果快表缺失,访问页表的次数由两次变为三次或者四次。由于程序可以访问的内存空间很大,如果程序的访存局部性不好,则会导致快表一直缺失,从而严重影响性能。

       此外,由于页表项有10M之多,而快表只能缓存几百页,即使程序的访存性能很好,在大内存耗费情况下,快表缺失的概率也很大。那么,有什么好的方法解决快表缺失吗?大页内存!假设我们将页大小变为1G,40G内存的页表项也只有40,快表完全不会缺失!即使缺失,由于表项很少,可以采用一级页表,缺失只会导致两次访存。这就是大页内存可以优化程序性能的根本原因—快表几乎不缺失!

       在前面我们提到如果要优化的程序耗费内存很少,或者访存局部性很好,大页内存的优化效果就会很不明显,现在我们应该明白其中缘由。如果程序耗费内存很少,比如只有几M,则页表项也很少,快表很有可能会完全缓存,即使缺失也可以通过一级页表替换。如果程序访存局部性也很好,那么在一段时间内,程序都访问相邻的内存,快表缺失的概率也很小。所以上述两种情况下,快表很难缺失所以大页内存就体现不出优势来。

你可能感兴趣的:(Linux相关,linux)