zoukankan      html  css  js  c++  java
  • Linux内存管理 (14)匿名页面生命周期

    专题:Linux内存管理专题

    关键词:匿名页面、换入、换出

    如果要将匿名页面的生命周期进行划分,大概就是诞生、使用、换出、换入和销毁。

    内核中使用匿名页面的地方有很多,产生缺页中断之后匿名页面就诞生了;

    用户进程访问虚拟地址即可访问到匿名页面内容;

    在内存紧张的时候,需要回收一些页面来释放内存,匿名页面可能被换出;

    如果虚拟地址空间被再次访问,则需要将swap分区中内容换入;

    当进程关闭或者退出时,VMA上的映射需要被清除,相关匿名页面会被销毁。

    1. 匿名页面的诞生

    从内核的角度看,出现匿名页面的情况有:

    1. 用户空间malloc/mmap接口函数来分配内存,在内核空间发生缺页中断时,调用do_anonymous_page()会产生匿名页面。

    2. 发生写时复制,当缺页中断出现写保护错误时,新分配的页面是匿名页面。

        2.1 do_wp_page(),只读的special映射的页面,例如映射到zeroed的页面;非单身匿名页面;只读的私有映射的page cache;KSM页面。

        2.2 do_cow_page(),共享的匿名页面(shared anonymous mapping, shmm)

    3. do_swap_page(),从swap分区 读回数据时会新分配匿名页面。

    4. 迁移页面

    2. 匿名页面的使用

    匿名页面在缺页中断中分配完成之后,就建立了进程虚拟地址空间VMA和物理页面的映射关系,用户进程访问虚拟地址即访问到匿名页面的内容。

    3. 匿名页面的换出

    假设系统内存紧张,需要回收一些页面来释放内存。

    anon_page刚分配时会加入活跃LRU链表(LRU_ACTIVE_ANON)头部,在经历了活跃LRU链表的一段时间的移动,

    该anon_page到达活跃LRU链表的尾部,shrink_active_list()函数把该页加入不活跃LRU链表(LRU_INACTIVE_LRU)。

    shrink_inactive_list()函数扫描不活跃链表,shrink_page_list()回首页面。

    (1) 第一次扫描不活跃链表时,shrink_page_list()->add_to_swap()函数会为该页分配swap分区空间

    此时匿名页面的_count、_mapcount、flags状态如下:

        page->_count = 3(引用计数增加的地方:1-分配页面;2-分离页面;3-add_to_swap())

        page->_mapcount = 0

        page->flags = PG_lru | PG_swapbacked PG_swapcache | PG_dirty | PG_uptedate | PG_locked,

    PG_swapcache表示该页已经分配了swap空间,PG_dirty表示该页为脏,稍后需要写回swap分区,PG_uptodate表示该也得数据是有效的。

    (2) shrink_page_list()->try_to_unmap()后该匿名页面状态如下

        page->_count = 2

        page->_mapcount = -1---------表示没有PTE映射该页

        try_to_unmap()会通过RMAP反响映射系统去寻找映射该页的所有VMA和相应的PTE,并将这些PTE解除映射。

        因为该页只和父进程建立了映射关系,因此_count和_mapcount都要减1。

    (3) shrink_page_list()->pageout()函数把该页写回交换分区,此时匿名页面状态如下

        page->_count = 2

        page->_mapcount = -1

        page->flags = PG_lru | PG_swapbacked | PG_swapcache | PG_dirty | PG_uptedate | PG_reclaim | PG_writeback

    (4) 第二次扫描不活跃链表

        经历第一次不活跃LRU链表的移动过程,从链表头移动到链表尾。

        如果这时该页还没有写入完成,即PG_writeback标志位还在,那么该页会继续被放回到不活跃LRU链表头,kswapd会继续扫描其它页,从而继续等待写完成。

        假设第二次扫描不活跃链表时,该页写入swap分区已经完成。Block Layer层毁掉函数end_swap_bio_write()->end_page_writeback()完成如下动作:

    • 清PG_writeback标志位
    • 唤醒等待在该页PG_writeback的线程,见wake_up_page(page, PG_writeback)函数。

    shrink_page_list()->__remove_mapping()执行后如下:

        page->_count = 0

        page->_mapcount = -1

        page->flags = PG_swapbacked | PG_uptedate

    最后把page加入free_page链表中,释放该页。因此该anon_page页的状态是页面内容已经写入swap分区,实际物理页面已经释放。

    4. 匿名页面的换入

    匿名页面被换出到swap分区后,如果应用程序需要读写这个页面,缺页中断发生。

    因为pte中的L_PTE_PRESENT比特位显示该物理页面不在内存中,但PTE表项不为空,说明该页被交换到swap分区去了,因此调用do_swap_page()函数重新读入该页的内容。

    5. 匿名页面销毁

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

  • 相关阅读:
    SpringMVC设置不拦截静态资源css,js
    关于Spring 国际化 No message found under code 的解决方案
    数据库中文乱码问题
    Maven下载清除jar包
    Swift学习笔记7:关闭
    bash构造tmux显示tmux ssh状态
    Mysql入门到精通数据表的操作
    MapReduce源代码分析MapTask分析
    世界目光聚焦美国:埃博拉病患者是否认真是可以治愈的?
    Android Studio如何引用jar包裹(不gradle)
  • 原文地址:https://www.cnblogs.com/arnoldlu/p/8335508.html
Copyright © 2011-2022 走看看