2.8:页面的定期换出 总结

主要的代码集中在2个内核线程kswapd和kreclaimd中,书中的分析主要集中在kswapd上。

Kswapd是一个无限循环,每过HZ个时间单位就被唤醒循环一次。每次循环中,使用inactive_shortage和free_shortage两个函数来判断是否存在可用物理页面短缺的情况。任何一个函数返回非零即认为物理页面短缺。

     出现物理页面短缺时,调用函数do_try_to_free_pages来腾出物理页面。函数首先调用free_shortage判断free状态的物理页面是否短缺,然后判断inactive_dirty状态的页面数量是否已经大于free和inactive_clean状态页面数量的总和。上述两个判断任何一个为非零则调用page_launder来扫描并处理inactive_dirty页面队列。Page_launder函数只负责处理inactive_dirty队列中的物理页面,其余的物理页面不属于此函数的处理范围。Page_launder首先对inactive_dirty队列中的每个物理页面做一些检查和处理,将不应在此队列中的物理页面调回active等等队列。确实应该在inactive_dirty队列中的page,如果正在使用(被I/O锁住),则调整至队尾。没有正在使用的page调用page->mapping->a_ops->writepage写回交换设备。如果page->buffer不为空,还需要调用try_to_free_buffers来处理。Try_to_free_buffers函数属于文件系统,本节未作深入分析。上述工作做完后,再调用free_shortage判断一次,如果结果仍然是非零,则重新对inactive_dirty队列中的page处理一次,然后page_launder函数返回。

Page_launder返回后,do_try_to_free_pages再次使用free_shortage+inactive_shortage判断物理页面情况。如果任何一个函数返回非零,则调用shrink_dcache_memory和shrink_icache_memory来释放文件数据和inode相关cache内存。本节未对这2个函数做深入分析。2个函数调用完成后,调用refill_inactive函数来处理active队列中的page。

Refill_inactive函数会以不同优先级扫描6次active队列,每次扫描的page数量逐次增加。每次循环中,调用refill_inactive_scan扫描active队列中的page,根据page结构中的PG_reference标志位来调整page结构中的age项。调用refill_active_scan时如果此标志位为1,则page最近被访问过,age增加PAGE_AGE_ADV(定义为3),否则age减半。当age为0的时候,如果page的引用计数为0(buffer不为空是如果引用计数为1)则将此page从active队列移至inactive_dirty队列。如果age不为0,则将此page移动至active队列的尾部。

Refill_inactive_scan返回后,refill_inactive的循环中接着调用swap_out来处理单个进程的active物理页面。每次swap_out只会处理1个进程,选择方法为:看看哪个进程中未被扫描过的物理页最多(mm->swap_cnt最大)。如果所有进程的mm->swap_cnt都为0,则重新将所有进程的此项数据初始化为进程专用所有物理页面的数量(mm->rss),然后选物理页面最多的。选出进程后,从vma向下至pgd,pmd逐pte进行处理。对于每个pte,调用try_to_swap_out。Try_to_swap_out首先根据pte的值找到对用页面的page结构,然后根据pte中的PAGE_ACCESSED标志位调整page结构中的age数据,调整方法与refill_inactive_scan一致。调整完成后,对于age为0的物理页面,如果此页面在交换设备上已经有对应的页面了,就增加交换设备上对应页面的使用计数,然后将交换设备对应页面的entry数据写入pte,此物理页面移至inactive_dirty队列。如果此时page只有引用计数为1,就进行buddy系统的合并。


你可能感兴趣的:(Linux,Kernel,内核,内存)