如果进过page_launder()后,如果可分配的物理页面数量仍然不足,那就要进一步设法回收页面,不过不是单纯的从各个进程的用户空间映射的页面中回收,而是其它方面回收,一个是文件关闭后并没立即释放的inode,dentry,作为LRU的后备,以防以后又要用到,用shrink_dcache_memory()和shrink_icache_memory()适当回收;一个是经由slab机制管理的动态分配的数据结构,它倾向于分配和保持过多的空闲物理页面,而不是热衷于换出,因此需要用kmem_cache_reap()来回收。
(1)在do_try_to_free_pages()中的refill_inactive()中,首先是通过kmem_cache_reap()回收由slab机制管理的空闲物理页面,相对而言该动作是很小的;然后从低优先级的开始来回收,判断task_struct中的need_resched是1的话,说明某一个中断服务程序需要调度,要求schedule()让内核再进行一次调度,但要把此进程设置成TASK_RUNNING,主要是因为内核线程永远不会返回用户空间(每当CPU结束一次系统调用和中断服务或从系统空间返回到用户空间时都会检查该标志),为了防止,占住CPU不放,自己调度离开;
(2)在循环中,用refill_inactive_scan()扫描活跃页面队列,试图找到可以转入到不活跃状态的页面;用swap_out()找出一个进程,然后扫描其映射表,从中可以找到不活跃状态的页面,此外,还要尝试dentry和inode结构的页面;在refill_inactive_scan()中,根据优先级来扫描活跃页面队列(优先级为0时是整个活跃页面队列),来设置和移动相应的page结构;
(3)swap_out()实际只是为把一些页面交换到交换设备上做准备,并不是物理意义上的换出;其中每一个进程中虚存页面对应在内存的集合,称为RSS;从init_task进程开始扫描一圈,找到最大的mm->swap_cnt反映的是该进程在一轮换出页面的努力中尚未受到考察的页面数量;如果一轮下来,没有找到这样的一个best对象,则设置assign再扫描一遍,跳到指定的标号select;而因最近因因异常换入(恢复映射)的页面,将会等到下一次扫描;