KSM (内存管理合并相同页)

KSM 是 Linux 内核的一项内存管理技术,通过合并相同内容的页面以节省内存,主要应用于虚拟化环境,但也适用于非虚拟化场景。KSM 通过定期扫描内存页面,检测并合并副本,释放额外空间。它使用红黑树结构存储页面,通过校验和比较判断页面是否相同。KSM 的启用、控制和监控可通过 sysfs 接口进行,提供资源利用效率和系统性能的提升。
摘要由CSDN通过智能技术生成

Ksm介绍

2.6.32引入了KSM(Kernel Samepage Merging)允许这个系统管理程序通过合并内存页面来增加并发虚拟机的数量。VMware 的 ESX 服务器系统管理程序将这个特性命名为 Transparent Page Sharing (TPS),而 XEN 将其称为 MemoryCoW。不管采用哪种名称和实现,这个特性都提供了更好的内存利用率,从而允许操作系统(KVM 的系统管理程序)过量使用内存,支持更多的应用程序或 VM。

假如操作系统和应用程序代码以及常量数据在 VMs 之间相同,那么这个特点就很有用。当页面惟一时,它们可以被合并,从而释放内存,供其他应用程序使用。

一台主机(Host)同时运行好几个相同类型的实例(guests),通过这种技术共享相同代码,比如每个guest的核心代码,那么随着guest实例增加,Host内存不会急剧的下降,有效的增加Host的provisioning能力。同时释放出内存,供其他系统或程序使用。这也是我们如何能够让一台16G内存的Server跑起52台1G内存XP系统的方法。VMware 的 ESX/ESXi 将这个特性定义为 Transparent Page Sharing (TPS),而 XEN 则将其称为 MemoryCoW (Copy-on-Write )。存储技术中的这种技术我们称为去耦合(de-duplication)。去耦合这种技术通过删除冗余数据(基于数据块,或者基于更大的数据片段,比如文件)来减少已存储的数据。公共数据片段被合并(以一种 copy-on-write [CoW] 方式),释放空间供其他用途。使用这种方法,存储成本更低,最终需要的存储器也更少。鉴于当前的数据增长速度,这个功能显得非常重要。

尽管 Linux 中的内存共享在虚拟环境中有优势(KSM 最初设计用于基于内核的虚拟机),但它在非虚拟环境中仍然有用。事实上,KSM 甚至在嵌入式 Linux 系统中也有用处,表明了这种方法的灵活性。

 

       KSM 作为内核中的守护进程(称为 ksmd)存在。它定期执行页面扫描,识别副本页面并合并副本,释放这些页面以供它用。

KSM 执行上述操作的过程对用户透明。例如,副本页面被合并,然后被标记为只读,但是,如果这个页面的其中一个用户由于某种原因更改该页面,该用户将以 CoW 方式收到自己的副本。可以在内核源代码 ./mm/ksm.c 中找到 KSM 内核模块的完整实现。

       KSM 应用程序编程接口(API)通过 madvise 系统调用和一个新的推荐参数MADV_MERGEABLE(表明已定义的区域可以合并)来实现。可以通过 MADV_UNMERGEABLE 参数(立即从一个区域取消合并任何已合并页面)从可合并状态删除一个区域。注意,通过 madvise 来删除一个页面区域可能会导致一个 EAGAIN 错误,因为该操作可能会在取消合并过程中耗尽内存,从而可能会导致更大的麻烦(内存不足情况)。     

一旦某个区域被定义为 “可合并”,KSM 将把该区域添加到它的工作内存列表。启用 KSM 时,它将搜索相同的页面,以写保护的 CoW 方式保留一个页面,释放另一个页面以供它用。

     KSM 使用的方法与内存去耦合中使用的方法不同。在传统的去耦合中,对象被散列化,然后使用散列值进行初始相似性检查。当散列值一致时,下一步是进行一个实际对象比较(本例中是一个内存比较),以便正式确定这些对象是否一致。KSM 在它的第一个实现中采用这种方法,但后来开发了一种更直观的方法来简化它。

     在当前的 KSM 中,页面通过两个 “红-黑” 树管理,其中一个 “红-黑” 树是临时的。第一个树称为不稳定树,用于存储还不能理解为稳定的新页面。换句话说,作为合并候选对象的页面(在一段时间内没有变化)存储在这个不稳定树中。不稳定树中的页面不是写保护的。第二个树称为稳定树,存储那些已经发现是稳定的且通过 KSM 合并的页面。为确定一个页面是否是稳定页面,KSM 使用了一个简单的 32 位校验和(checksum)。当一个页面被扫描时,它的校验和被计算且与该页面存储在一起。在一次后续扫描中,如果新计算的校验和不等于此前计算的校验和,则该页面正在更改,因此不是一个合格的合并候选对象。

     使用 KSM 进程处理一个单一的页面时,第一步是检查是否能够在稳定树中发现该页面。搜索稳定树的过程很有趣,因为每个页面都被视为一个非常大的数字(页面的内容)。一个 memcmp(内存比较)操作将在该页面和相关节点的页面上执行。如果 memcmp 返回 0,则页面相同,发现一个匹配值。反之,如果 memcmp 返回 -1,则表示候选页面小于当前节点的页面;如果返回 1,则表示候选页面大于当前节点的页面。尽管比较 4KB 的页面似乎是相当重量级的比较,但是在多数情况下,一旦发现一个差异,memcmp 将提前结束。

     如果候选页面位于稳定树中,则该页面被合并,候选页面被释放。反之,如果没有发现候选页面,则应转到不稳定树。

     在不稳定树中搜索时,第一步是重新计算页面上的校验和。如果该值与原始校验和不同,则本次扫描的后续搜索将抛弃这个页面(因为它更改了,不值得跟踪)。如果校验和没有更改,则会搜索不稳定树以寻找候选页面。不稳定树的处理与稳定树的处理有一些不同。第一,如果搜索代码没有在不稳定树中发现页面,则在不稳定树中为该页面添加一个新节点。但是如果在不稳定树中发现了页面,则合并该页面,然后将该节点迁移到稳定树中。

     当扫描完成时,稳定树被保存下来,但不稳定树则被删除并在下一次扫描时重新构建。这个过程大大简化了工作,因为不稳定树的组织方式可以根据页面的变化而变化。由于稳定树中的所有页面都是写保护的,因此当一个页面试图被写入时将生成一个页面故障,从而允许 CoW 进程为写入程序取消页面合并(break_cow())。稳定树中的孤立页面将在稍后被删除。

 

Ksm实现

static int __init ksm_init(void) 用于ksm初始化:

1、创建ksmd线程,该线程用于物理页面扫描合并:

ksm_thread= kthread_run(ksm_scan_thread, NULL, "ksmd");

 

2、创建sysfs的配置和监控,下章节介绍:

         err = sysfs_create_group(mm_kobj,&ksm_attr_group);

         if (err) {

                   printk(KERN_ERR "ksm:register sysfs failed\n");

                   kthread_stop(ksm_thread);

                   goto out_free2;

         }

 

主函数ksm_scan_thread为一个非实时任务,循环进行页合并操作:

staticint ksm_scan_thread(void *nothing)

{

         set_user_nice(current,5); 设置成nice值为5非实时任务

 

         while (!kthread_should_stop()) {

                   mutex_lock(&ksm_thread_mutex);

                   if (ksmd_should_run())

                            ksm_do_scan(ksm_thread_pages_to_scan);一次扫描成功ksm_thread_pages_to_scan页返回

                   mutex_unlock(&ksm_thread_mutex);

 

                   if (ksmd_should_run()) {

                            schedule_timeout_interruptible(

                                     msecs_to_jiffies(ksm_thread_sleep_millisecs));休息ksm_thread_sleep_millisecs时间后进行下一次扫描

                   } else {

                            wait_event_interruptible(ksm_thread_wait,

                                     ksmd_should_run()|| kthread_should_stop());

                   }

         }

         return 0;

}

 

首先介绍一个数据结构rmap_item反向映射条目,该条目保存有物理地址到虚拟地址的反向映射,同时用来组织稳定树的红黑树结构,对于非稳定树保存有校验和。

structrmap_item {

         struct list_head link;

         struct mm_struct *mm;

         unsigned long address;             /* + low bits used for flags below*/

         union {

                   unsigned int oldchecksum;                /* when unstable */

                   struct rmap_item *next;                            /* when stable */

         };

         union {

                   struct rb_node node;                          /* when tree node */

                   struct rmap_item *prev;                            /* in stable list */

         };

};

页合并主函数ksm_do_scan首先根据扫描区间获得一个page,并为其建立反向映射条目。接着对该页在稳定树和非稳定树中寻找相同的页进行比较与合并。

staticvoid ksm_do_scan(unsigned int scan_npages)

{

         struct rmap_item *rmap_item;

         struct page *page;

 

         while (scan_npages--) {

                   cond_resched();

                   rmap_item =scan_get_next_rmap_item(&page);//对扫描区间的每一个页进行扫描

                   if (!rmap_item)

                

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值