Hugemem Kernel Explained


 红旗DC系列Linux操作系统(x86平台)中带有四类核心:

    * UP (支持单内核)
    * SMP (支持多内核)
    * hugemem
    * Icc* (用intel C编译器编译的核心)


其中hugemem核心往往引起很多困惑,这里希望能一劳永逸地把hugemem解释清楚。


Hugemem vs. SMP

x86平台下, 红旗DC4.1和5.0所带的smp和hugemem核心都打开了PAE支持,也就是说都可以支持4G以上的物理内存。引入hugememe核心的目的_不是_支持超过4G物理内存(SMP核心就可以支持了),而是更稳定地支持大内存x86系统(所谓大内存可以简单理解为超过12G内存的系统)。


smp和hugemem核心的 _唯一_区别是hugemem核心中打入了4G/4G补丁,使用4G/4G补丁可以将直接映射的内核数据代码地址空间从1G扩大到4G,将进程的虚拟地址空间也由 3G扩大到4G。当物理内存过多时,管理这些物理内存的工作本身会占用不少宝贵的内核地址空间(所谓低端内存),此时虽然总的物理内存还有不少空闲,由于低端内存耗尽,也可能会导致内存紧张,触发OOM (Out of memory) killer,导致应用终止甚至核心崩溃。


如果超过12G物理内存,一般建议使用hugemem内核。不过,hugemem会带来一定的性能损失。


以上说明对于一般用户应该足够了,如果想了解4G/4G补丁的更多细节,请继续往下看...

大内存x86系统带来的问题


4G/4G补丁主要应用于大内存x86系统(所谓大内存可以简单理解为超过12G内存的系统),这样的系统往往需要更多的内核地址空间和用户地址空间。

在x86架构下,我们知道虚拟地址空间的大小为4G。在这4G空间中,用户空间占3G (0x00000000到0xbfffffff),核心空间占1G(0xc0000000到0xffffffff)。这样的分配策略成为3G/1G分配。这种分配方式对于拥有1G物理内存以下的系统是没有任何问题的,即使超过1G物理内存,3G/1G分配策略也没有什么问题,因为内核可以在高端内存区域 (物理地址1G以上的内存)中存放一些内核数据结构(比如页缓冲等)。然而,随着物理内存的增多,3G/1G分配策略的问题也逐渐会暴露出来。这是因为一些关键的内核数据结构(比如用于管理物理内存的mem_map[])是存放在1G核心空间之内的。对于32G内存的系统,mem_map[]会占用近 0.5G的低端内存(物理地址896M以下的内存),这样留给核心其他部分的内存就不到所有内存的1.5%;而对于64G内存的系统,mem_map[] 本身就会耗尽所有的低端内存,造成系统无法启动。把mem_map[]放到高端内存的做法也不太实际,因为mem_map[]和内存管理,体系结构相关底层实现,文件系统以及驱动等几乎所有的核心的关键部分均有联系。

4G/4G的作用

与3G/1G不同,4G/4G分配方式可以使核心空间由1G增加到4G,而用户空间也由3G增加到4G。从 /proc/PID/maps 文件中可以直观地看到4G/4G所起的作用:


00e80000-00faf000 r-xp 00000000 03:01 175909 /lib/tls/libc-2.3.2.so

00faf000-00fb2000 rw-p 0012f000 03:01 175909 /lib/tls/libc-2.3.2.so

[...]

feffe000-ff000000 rwxp fffff000 00:00 0


从上面的maps可以看出,堆栈的栈底地址为0xff000000 (4GB 减去 16MB)。

从/proc/maps中则可以看到核心拥有了4G大小的低端内存,即使对于64G物理内存的系统,也有3.1G低端内存可供使用:


MemTotal: 66052020 kB

MemFree: 65958260 kB

HighTotal: 62914556 kB

HighFree: 62853140 kB

LowTotal: 3137464 kB

LowFree: 3105120 kB


相比3G/1G分配策略,对于4G物理内存系统,使用4G/4G分配可以增加低端内存达3倍以上,而对于32G物理内存系统,则会有更多的提升,达到原来的6倍。 理论上,4G/4G策略可以支持物理内存达200G的x86系统(如果硬件没有限制的话),即使对于这样的系统,4G/4G策略也能保证留有1G可用的低端内存。

4G/4G的代价

天下没有免费的午餐,4G/4G也是如此。4G/4G通过完全分离用户空间和核心空间的地址映射来增加低端内存,这样做会带来一些性能损失,具体而言,当发生上下文切换的时候(比如进程调用系统调用或者发生中断),必须重新装载页表(3G/1G策略下不需要加载,因为核心可以直接“借用”每个进程的页表进行内存映射),页表的重新装载后必须清空TLB(否则的话TLB中记录的映射就和新的页表不一致了),而清空TLB是一个很费时的操作,原先缓存于 TLB中的“旧”的映射会被丢掉,这一损失到还在其次(因为不经TLB直接从CPU缓存中读取页表也并不会有太大延迟),最大的损失在于清空TLB(通过操作%cr3)这个操作本身代价很高。

何时使用(or不使用)4G/4G?

对于这个问题,没有放之四海而皆准的答案。只有一些拇指定律。一般情况下,超过16G内存几乎肯定需要使用4G/4G (除非运行的应用负载很轻,不过大内存系统很少有负载轻的情况),如果负载很重(不如运行数据库进行着大量I/O操作),那么12G以上的系统就应考虑使用4G/4G。也可以通过观察空闲低端内存大小来大体判断一下(/proc/meminfo),如果空闲低端内存(LowFree)小于100M,那么就可以考虑使用4G/4G了。8G以下的系统一般不必使用4G/4G。


需要指出的是,如果需要大内存,最好的解决方法是用64位系统,而不是使用4G/4G。

 

 原文地址 http://x.uplinux.com/?2/action_viewspace_itemid_26.html

你可能感兴趣的:(数据结构,数据库,linux,平台,编译器,X86)