详细讲解Linux内存管理之页面回收
发布网友
发布时间:2024-10-03 02:03
我来回答
共1个回答
热心网友
时间:2024-11-06 04:25
请求调页机制允许用户态进程获取页框,然而,没有机制强制进程释放不再使用的页框。Linux内核的页面回收算法(PFRA)采用从用户进程和内核高速缓存“窃取”页框的方式解决这一问题,而非从伙伴系统的空闲块列表。在用完所有空闲内存之前,必须执行页框回收算法,否则内核可能陷入内存请求的僵局,导致系统崩溃。PFRA目标是安全地从“内存紧缺”的情形中恢复,通过释放最少的空闲页框。
PFRA通过检查页框所含内容,以不同的方式处理页框:不可回收页、可交换页、可同步页和可丢弃页。选择目标页是PFRA的关键步骤,其目标是释放页框并使之空闲。为此,PFRA采用多种策略:首先释放“无害”页,即未被任何进程使用的磁盘与内存高速缓存中的页;将用户态进程和所有页定为可回首页,以便PFRA能够窃得任何用户态进程页;取消引用一个共享页的所有页表项的映射以回收该共享页;仅回收“未用”页,使用LRU算法确定页的使用情况。
PFRA的设计包括谨慎选择检查高速缓存的顺序、基于页年龄排序、区别对待不同状态的页等策略。在释放页框时,PFRA利用反向映射技术快速确定指向同一页框的所有页表项。Linux内核为物理页面建立链表,记录引用页面的所有页表项。基于对象的反向映射技术使得PFRA能够检索引用某页的所有页表项,实现高效释放共享页框。
PFRA通过双向链表和优先级搜索树等数据结构管理匿名页面和文件映射页面的反向链接,实现快速定位引用页面的所有页表项。双向链表存储匿名页面的内存区域,而优先级搜索树用于文件映射页面,通过大小、起始和结束位置等属性实现高效查找。
在页面回收过程中,Linux内核通过shrink_page_list()函数更新所有引用回收页面的页表项,实现反向映射的自动化。该函数检查并确定都有哪些页表项引用了同一个物理页面。匿名页面和文件映射页面分别采用不同的方法,匿名页面通过遍历anon_vma表,文件映射页面通过优先级搜索树搜索。回收页面的关键代码流程包括更新页表项,处理不可回收页面,以及更新页面使用计数器等。
LRU(最近最少使用)链表在Linux中实现页面活跃状态的管理,通过active和inactive两个链表区分活跃和不活跃页面。活跃页面被放置在active链表中,不活跃页面被放置在inactive链表中。页面在两个链表之间移动,基于其活跃程度,Linux使用两个页面标志符PG_active和PG_referenced来判断页面的活跃程度,确保页面的高效管理。
为了降低锁的竞争,Linux引入了LRU缓存机制,通过批量添加页面到链表,避免频繁使用自旋锁。LRU缓存使用pagevec结构管理缓存页面,并通过lru_cache_add()和lru_cache_add_active()函数实现页面的延迟添加。页面在LRU链表之间移动的过程可以通过锁的竞争和LRU缓存的使用来优化。
PFRA的具体实现包括处理用户态进程、磁盘高速缓存和内存高速缓存中的页。核心函数如try_to_free_pages()和balance_pgdat()触发页面回收,分别在内存严重不足或后台进程检测到内存不足时执行。函数shrink_zones()和shrink_slab()在内存区域列表中释放页面,shrink_zone()和shrink_slab()实现页面回收的细节操作。