2015年12月16日星期三

KSM continued

地址空间共享

基于UNIX的OS通过forking创建子进程时,新建子进程的地址空间拷贝了forking process原有地址空间的内容,OS实际上使用了copt-on-write的形式将父进程的地址空间与子进程共享而不是去复制RAM中的内存内容。

文件系统cache共享

原先加载的文件通常会缓存在操作系统的文件缓存中(page cache)。文件可以被映射至内存中为了更容易和高效的非线性访问,比如mmap系统调用。多个映射同一文件的此类映射在文件缓存中是共享的。程序的二进制镜像和动态共享库通常是依赖这种机制实现的。这种机制的限制是仅能共享来自同一源对象的内存区域,依旧是拥有相同inode的内存区域。当文件被拷贝,两个文件不再在内存中共享。

虚拟机内存共享

semantic gap阻碍了虚拟机之间在宿主机上物理内存的共享。

Anonymous memory
匿名内存及组成此类内存的内存页在任意存储层级上没有自然表示,典型的例子是运行进程的堆栈空间。匿名内存内容不能在未明确写入后台存储中特定磁盘区域时替换出内存。
Named memory
命名内存页与其相反,它在存储栈上拥有一个自然表示,通常这是磁盘上的一个文件。此类文件的例子是文件映射至内存,指定映射共享库或进程的 文本段。命名页替换出内存时源文件内容未修改的直接丢弃即可,假如映射至内存的文件页发生过改动,修改应写回至原始文件。


page struct

_count 页框被虚拟页应用的次数
_mapcount 这个页框被几个页表项应用
mapping  上下文敏感的语义。命名内存的页框指向文件缓存中描述文件映射的数据结构,index描述这个页框在所表示的文件中的偏移。匿名内存情况下,mapping指向了一个链表,这个链表包含了所有的引用了此页框的虚拟内存空间VMA。

The address space of each task(process or thread) is described in memory descriptor.这个描述符由一系列内存域VMAs构成。每个VMA代表任务虚拟地址空间中的一段。
task_struct            进程
         mm_struct       地址空间
                  vm_area_struct        虚拟地址段

OS会为每个内存区域指定标识vm_flags。这些标识描述了这个内存域应当被如何使用。也决定了在映射时OS如何对应的PTE标志位。


KSM数据结构
Revere Mapping Item
rmap_item得名与它的功能是将合并页的物理页框号(Kpfn)转换为虚拟地址并按COW形式使用页框号。 rmap_item包含了如下信息:
  • 序列码(地址的低比特位)表示此页在过去被多么频繁的访问到
  • jhash2校验码,上次访问此页时根据页内容计算得到
  • state(同样编码在地址的低阶比特位)也反映了本项在哪个数据结构中(mm_slot,unstable tree, stable tree)
  • 指向它地址空间中下一项的指针
mm_slot 包含了提交到去重所有地址范围的有序链表。 应用程序可以从其拥有的地址空间中向mm_slot中增加新的范围,通过调用系统调用madvise以及MADV_MERGEABLE标志位。假如在同一MM中已经存在了可合并的区域,那么新内存区域会被添加到mm的rmap_list中,通过为域内的每页创建新的rmap_item并将它们插入到链表中。

KSM cursor:在每个系统中只存在这ksm_cursor结构体的单一实例。它保存了当前遍历所有mm_slots中rmap_item的线性扫描进程的信息。为此,它包含了当前进程指向mm_slot和rmap_item的指针以及要扫描的下一个地址。

以unstable tree为例,rmap_item如何组成树结构:

属于unstable_tree的rmap_item通过address域的地位的UNSTABLE_FLAG表征。

 树的索引是插入页的全部内容,为了在树中查找与页A相同的页,需将根节点的开始若干字节需要与页A的字节进行比较直至出现不同字节。若A中的异字节小于根节点,KSM继续沿左分支查找,反之查找右分支,重复之前的比较过程直至叶子节点。非稳定树中的页的引用不会受到写保护,也就是说那些由页内容决定的索引也会随时间发生改变,使得树发生混乱,造成有的结点不可达。

与unstable树相反,稳定树中的合并页被设置为COW也就是写保护的,稳定树中的页的内容保持它们被插入树时的内容,即使页已被unmapped。 去映射发生在写时拷贝引用页,状态的改变可以在扫描时检测到。过期的项会被移除出稳定树。

非稳定树与稳定树的另一个差异是,在非稳定树中发现多个项指向同一页内容是一个异常。而在稳定树中,正常的情形是,多个项共享同样的内容。由于不同的使用场景,两个额外域被用于引用rmap_item当它属于稳定树。









 rmap_item包含一个链表hlsit,将所有共享相同合并页框kpfn的rmap_item串联起来。

 Programs inform the kernel, that they want a certain address range to be deduplicated, using the madvise system call with the MADV_MERGEABLE flag. The OS forwards memory regions that are advised to be mergeable to KSM. The scanner
then inserts the VMA and issued address range to the mm_slot data structure right
before the current scan cursor. This way, the advised memory area has time to settle
down before the scan thread visits it for the first time. In its current implementation,
KSM only allows setting MADV_MERGEABLE on pages with 4 KiB page-size.

一段地址范围过后可以通过调用madvise系统调用MADV_UNMERGEABLE标志排除出去重扫描器。然后,该地址范围内的页的共享将被破坏,这段地址范围也会从mm_slot中清除。

KSM并不会增加mm_slot内页的引用计数器。KSM不需要再扫描对应页时锁定页,使用了page_cache_get_speculative()机制访问页却不引用页。

选择下一个页:KSM扫描的是虚拟页地址空间。KSM基于mm_slot数据结构中的顺序选择下个要扫描页。每个mm中的建议页安正地址增长的顺序被扫描。在唤醒间隔ksm_cursor存储当前扫描位置。假如这个接下来原定要扫描的虚拟页的反向重映射项不存在,那么这个位置就变成首次分配的新rmap_item。否则使用之前分配的rmap_item。在扫描过程中,扫描会跳过无效页。也就是它会忽略当前不在内存中的索引页,比如交换至底盘中的页。而且,KSM也不会访问已经位于stable树中的页,通过rmap_item中STABLE_FLAG标识。

Scan Rounds当扫描到最后一个mm_slot的最后一个memory area时,KSM完成一个整个扫描回合。它会通过置非稳定树根节点指针为NULL丢弃掉unstable tree。 然而,rmap_items仍然是通过它们所在mm_slot可达的并未释放掉。oldchecksum和整个stable tree保持不变。

扫描的过程是完全单线程的。






没有评论:

发表评论