linux源码解析15- 匿名页面的生命周期

时间:2023-02-22 15:22:33

1.匿名页面的产生

从内核角度看,如下情况会产生匿名页面:

1.1 用户空间malloc()/mmap()分配的内存;

在内核发生缺页中断时,调用do_anonymous_page()产生匿名页;

1.2 写时复制:

当缺页终端出现写保护错误时,分两种情况:

(1)调用do_wp_page()函数分配 a.只读的special映射的页,例如映射到zero_page的页面; b.多个映射的匿名页面,即page->_mapcount>0; c.只读的私有映射的内容的page cache; d.KSM页面;

(2)调用do_cow_page()函数分配的共享匿名页面(shmm);

这些写时复制,会新分配匿名页面;

(3)do_swap_page(): 从swap分区读回数据时新分配匿名页面;

(4)迁移页面:

调用do_anonymous_page()分配一个匿名页面初始状态:

page->_refcount=1;
page->_mapcount=0 ;
设置PG_swapbacked标志;
加入LRU_ACTIVE_ANON链表,并设置PG_lru标志;
page->mapping指向vma的av结构;

2.匿名页面的使用:

在缺页异常处理时,就建立了虚拟地址到page的映射;用户进程访问虚拟地址即访问匿名页面的内容;

3.匿名页面的换出:

系统内存紧缺时,需要回收一些页面来释放内存; 匿名页面刚分配时加入到活跃链表LRU_ACTIVE_ANON头部,在活跃LRU链表移动一段时间后,到达活跃LRU尾部;

shrink_page_list()函数把该页面加入不活跃LRU链表LRU_INACTIVE_ANON;

shrink_page_list(); //活跃链表->不活跃链表

第一次扫描不活跃链表

为该页面分配swap分区空间;

shrink_page_list()->add_to_swap()

此时匿名页状态;

page->_refcount = 3;
page->_mapcount = 0;
page->flags = PG_lru|PG_swapbacked|PG_swapcache|PG_dirty|PG_uptodate|PG_locked;

注:分离链表时_refcount++,add_to_swap()也会让_refcount++,所以这里_refcount=3;

add_to_swap()还增加若干个页面标志位;

shrink_page_list()->try_to_unmap() 通过RMAP去寻找所有索引映射的VMA和PTE,并解除映射,运行后,匿名页状态:

page->_refcount = 2;
page->_mapcount = -1;//没有pte映射,已经解除

shrink_page_list()->pageout() 把页面写回swap分区,page状态

page->_refcount = 2;
page->_mapcount = -1;//没有pte映射,已经解除
page->flags = PG_lru|PG_swapbacked|PG_swapcache|PG_reclaim|PG_writeback;

pageout()函数作用:

检查该页面是否可以释放; 清除PG_dirty标志位; 设置PG_reclaim标志; 调用swap_writepage设置PG_writeback,清除PG_lock; 在向交换分区写内容时,kswapd不会一直等该页面写完,而是将该页面放回不活跃LRU链表头部;

第二次扫描不活跃链表

若写swap还没完成,PG_writeback标志位还在,继续放入不活跃链表头部;

写入swap分区已完成,Blocklayer层回调end_swap_bio_write()>end_page_writeback();完成如下操作:

清除PG_writeback标志位; 唤醒等待在该页的写回线程,wake_up_page(page,PG_writeback);

shink_page_list->__remove_mapping()

page_freeze_refs(page,2);//判断page->_refcount是否为2,并且将计数设置0
清PG_swapcache标志位
清PG_locked标志位

此时page状态:

page->_refcount = 0;
page-_mapcount=-1
	page->flages =(PG_update|PG_swapbacked)

最后把page加入free_page链表中,释放该页; 因此,该匿名页面的转台是页面内容已经被写入交换分区,实际物理页面已经释放;

4.匿名页面的换入

匿名页面换出到swap分区后,如果应用程序要读写这个页面,会触发缺页中断,由于pte不为空,且pte->present不在内存中;

调用do_swap_page()函数重新读取该页面内容。

5.匿名页面的销毁

当用户进程关闭或者退出时,扫描这个用户进程所有vma,并清除vma上的所有映射,如果符合释放标准,相关页面会被释放;

下图概括匿名页的整个生命周期;

周期图.jpg