cow:copy on write,也就是写时复制。这是一种内存共享技术,在linux中当使用fork 函数创建一个进程时,子进程和父进程共享全部的内存,当这片共享的内存区域被进程试图修改的时候,内核会分配一块新的内存区域,并将被试图修改的共享内存区域复制到新的内存区域上,然后再让进程去修改内存区域。
ksm:kernel SamePage Merging。 ksm让内核扫描正在运行中的所有程序,并比较它们的内存,如果发现它们的内存页有相同的,那么就把它们相同的内存页合并为一个内存页,并将其标识为“写时复制”,当标识为“写时复制”的内存页需要被修改时,内核就为其分配新的内存空间,并复制内存页到新的空间,在新的内存空间上进行修改。
ksm设计初衷就是为了给虚拟化节约内存的,因为如果客户机都使用相同的系统和运行类似的程序,那么每个客户机进程就会有很大一部分的内存页是相同的,这时候使用ksm技术就能大大降低内存的使用率。也方便kvm内存的过载使用,传说有人在16G内存的机器上,成功运行52个1G内存的xp客户机。
所以ksm的优点显而易见,但是它的缺点也是很明显的。ksm需要扫描相同的内存页,这就带来了开销,而且ksm自身也需要占用内存,当机器运行的程序没有什么耦合度的话,那么ksm不见得能提升内存效率。而且使用ksm还需要保证足够的内存交换空间,因为我们把多个内存页合并为一个,当内存耗尽,而恰好有内存页需要修改时,此时内存就溢出了,所以需要swap交换空间过渡下。
内核的ksm守护进程时ksmd,我们可以通过修改/sys/kernel/mm/ksm/下的ksmd参数来对其进行配置,它的参数有如下几种(参考https://www.kernel.org/doc/Documentation/vm/ksm.txt):
full_scans:对可合并的内存区域扫描过的次数。
merge_across_nodes: 在NUMA架构的平台上,是否允许跨节点(node)合并内存页。
pages_shared:记录合并后共有多少内存页。
pages_sharing:记录有多少内存页正在使用被合并的共享页,不包括合并的内存页本身。
pages_to_scan:ksmd进程休眠前扫描的内存页个数。
pages_unshared:因为没有重复内容而不能被合并的内存页数量
pages_volatile:因为内容很容易变化而不能被合并的内存页数量
sleep_millisecs: ksmd进程休眠的时间(单位:毫秒)
run:是否开启ksm
0:表示停止ksmd但保持它已经合并的内存页
1:运行ksmd
2:停止ksmd并分离已合并的内存页
pages_sharing 的值越大,说明KSM节省的内存越多,KSM效果越好。
pages_sharing 除以 pages_shared 得到的值越大,说明内存页重复的次数越多,KSM效率越高。
pages_unshared 除以 pages_sharing 得到的值越大,说明不能合并的内存页越多,KSM效率越低。
Redhat 系列系统有提供了两个服务ksm和ksmtuned,动态调节KSM的运行情况。
而ubuntu默认没有KSM服务, 如果需要使用则安装ksmtuned服务
ksm:操作ksmd的功能,也就是利用这个脚本可以echo “$num" >/sys/kernel/mm/ksm/PARAMATER
ksmtuned:可以智能地判断什么时候该开启ksmd什么时候该关闭并调节ksmd参数的程序,其配置文件为/etc/ksmtuned.conf