ksm(Kernel Samepage Merging)是linux内核中一个feature,通过合并内存中的相同页面来减小内存占用,常用语虚拟化中。
ksm合并的一般是用户分配的内存(能不能用在内核页面我还不清楚)。关键的是它只能合并私有的匿名页面。想了解更多的有关页面的分类可以查看man mmap。如果想让自己分配的页面可以被ksm优化,那就必须显示声明出来。方法是使用madvise接口,一般是:madvise(addr, length, MADV_MERGEABLE); addr是内存地址,length是长度,MADV_MERGEABLE就是表示要让内存可以被ksm优化。声明之后,内核就会把这段内存加入到ksm的扫描列表里面。
我们重点来看看使用madvise之后内核对内存的检查,这样我们就能更深入地知道ksm的适用范围。
调用madvise后内核处理函数从madvise_behavior跳到ksm_madvise,这个函数处理MADV_MERGEABLE case的部分如下:
case MADV_MERGEABLE:
/*
* Be somewhat over-protective for now!
*/
if (*vm_flags & (VM_MERGEABLE | VM_SHARED | VM_MAYSHARE |
VM_PFNMAP | VM_IO | VM_DONTEXPAND |
VM_HUGETLB | VM_MIXEDMAP))
return 0; /* just ignore the advice */
if (vma_is_dax(vma))
return 0;
...
...
if (!test_bit(MMF_VM_MERGEABLE, &mm->flags)) {
err = __ksm_enter(mm);
if (err)
真正将内存加入ksm扫描列表的是__ksm_enter,在此之前有很长的检查代码。从检查代码里我们可以看到,对于共享的或io或是大页内存将不做进一步处理的。
其实从man madvise中我们可以得到更明确的说明:
MADV_MERGEABLE (since Linux 2.6.32)
Enable Kernel Samepage Merging (KSM) for the pages in the range specified by
addr and length. The kernel regularly scans those areas of user memory that
have been marked as mergeable, looking for pages with identical content. These
are replaced by a single write-protected page (which is automatically copied if
a process later wants to update the content of the page). KSM merges only pri‐
vate anonymous pages (see mmap(2)).
这给我们一个比较明确的提示,一旦你分配的内存是共享的或者是大页,ksm就跟你无缘了。