深入理解反向映射

2022-02-11 07:52:22 浏览数 (1)

作者:Cheetah老师一直从业于半导体行业,他曾为U-boot社区和Linux内核社区提交过若干补丁。目前主要从事Linux相关系统软件开发工作,负责Soc芯片BringUp及系统软件开发,喜欢阅读内核源代码,在不断的学习和工作中深入理解内存管理,进程调度,文件系统,设备驱动等内核子系统。

图:反向映射的基本概念

图:反向映射的原理

图:反向映射应用之内存回收

第一个场景是内存回收,内存不足时内核会从不活跃的lru链表尾部回收一些页面,而对于映射到进程地址空间的物理页面,我们需要在回收之前对他做解除映射处理。

对于匿名页,由于里面的数据是进程运行过程中产生的有用数据,不能随意丢弃,需要交换到交换分区,然后通过反向映射查找映射这个物理页的每个页表项,然后将页表项修改为换出页标识符(通过它能知道匿名页被交换到哪个交换分区,哪个位置)。再次访问匿名页时通过换出页标识符即可将所需的数据页从交换分区换入再建立页表映射即可。

而对于文件页,如果是“干净的”文件页,是可以直接丢弃回收。由于文件页有后备文件支持,再次访问文件页时,将所需的数据页从文件中读取到内存建立页表映射即可。

图:反向映射应用之页面迁移

第二个场景是页面迁移,页面迁移在内核的CMA、内存碎片整理等被广泛使用。在迁移页面的时候,如果是映射页,会调用try_to_unmap将映射这个物理页的每个页表项修改为迁移类型表项。迁移过程中,进程再次访问会发生swap缺页异常,异常处理中判断为迁移类型表项就会是进程睡眠等待迁移完成。

图:反向映射应用之脏页跟踪(1)

图:反向映射应用之脏页跟踪(2)

第三个场景是脏页跟踪,对于共享的文件页,由于文件页被多个进程共享,linux内核通过页表项的“脏”标记跟踪页面为脏。每一次回写时,都会调用clear_page_dirty_for_io函数,这个函数会通过反向映射将映射这个页面的每个页表项都修改为只读并清脏标记。再次访问时,发生写实复制缺页异常,异常处理中再次设置页表项为脏、可写,从而跟踪了脏页。

图:反向映射应用场景之访问跟踪

还有个场景是访问跟踪,linux内核通过页表项的“访问”标记跟踪页面被访问。页面回收算法中,对于活跃的lru和不活跃的lru链表,在扫描映射页时,都会通过page_referenced函数统计页面被访问的次数,从而判断页面最近的活跃程度,将不活跃的页面回收。当页表项的访问标志是清除状态时,访问会发生访问权限的缺页异常,然后重新设置访问标志,就对页面进行了访问跟踪。

0 人点赞