内核内存回收原理简介

这篇博客详细介绍了内核内存回收的过程,包括页框回收的原理、页高速缓存的数据结构和操作,以及交换子系统的概念和操作流程。讨论了页的转换图、反向匿名映射的作用,以及在内存紧张时如何通过交换将页换出到磁盘,以回收内存并维持内核正常运行。
摘要由CSDN通过智能技术生成

页框回收与交换

概念

内核在为进程服务的过程中会分配大量的页,但是这些页对应的虚拟地址在进程的生命周期里一直会被断断续续的访问,所以当内核同时为大量进程服务时,内存终究会耗尽。所有页框回收就是在内核未耗尽内存之前(因为回收与交换也会使用内存),将在使用过程标记未访问不频繁的部分内存换出到磁盘,释放所占用的内存补给系统,以维持内核的正常运转,待被换出的页对应的虚拟地址再次被访问时,内核又通过缺页系统将换出的页再次分配新的内存进行换入,这样周而复始形成良性的循环。

组成

每个zone中都有一套lrubuddy system

  1. 页:可回收的页
  2. 最近使用链表lru:页描述符的标记和放置使用页的活动与不活动链表,使用过程中通过对页的访问,判断页是否是活动的,从而在活动与非活动链表中来回移动。
  3. 算法和守护线程:内存分配子系统中的页的直接回收路径与守护线程,他们负责计算应该将什么也标记为可回收状态、回收的数量是多少,然后触发或执行回收过程(扫描非活动链表开始回收)。
  4. 交换分区:交换分区页高速缓存与交换分区磁盘(或文件),他们负责暂存页引用和存储页的数据。
  5. 文件和设备:文件页高速缓存与文件(或设备),他们负责暂存页引用和回写脏页数据。

参与页框回收的页类型

type comments reclaimed operation
不可回收 1. 活动系统中的空闲页
2. 保留页(PG_reserved置位,比如内核镜像页)
3. 内核使用的动态分配的页
4. 进程内核态堆栈页
5. 临时锁定的页(PG_locked置位)
不允许回收或无需回收
可交换页 1. 用户态进程匿名页
2. tmpfs文件系统的映射页(比如IPC共享内存页)
将页交换到交换分区
可同步页 1. 用户态进程映射页
2. 存有磁盘文件数据页且在文件页高速缓存中
3. 块设备缓冲区页
4. 磁盘高速缓存页(索引节点高速缓存)
必要时,与磁盘同步这些页
可丢弃页 1. 内存高速缓存中未使用的页(比如slab分配器的未使用对象缓存)
2. 目录项高速缓存的未使用页
释放这些页,压缩缓存

页的转换图

  1. 每个zone中都有一套lrubuddy system
  2. 每个CPU有一套lru-cache
  1. 页的转换
                          +--------------------+
        +---->>>-----+--->| inactive lru cache |--->-+
        ^            ^    +--------------------+     |
        |            |                               |
        |            |                               v
        |      +-----+------+               +--------+-----+
        |      | active lru |               | inactive lru |
        |      +-----+------+               +--------------+
        |            ^                               |      
        |            |                               |      
        +---->>>-----+--<<<--+                       |      
        |                    |                       |      
    +---+-------+      +-----+------------+          v      
    | lru cache |      | active lru cache |          v      
    +---+-------+      +-----+------------+          v      
        ^                    |                       |      
        |                    |                       |      
        |                    |         re-active     |      
   PAGE |                    +-----<<<<<-------------+       
        |                                            |      
  +-----+-----+                     start reclaimed  |        +-----------------+
  | buddy sys |                 +--------<<<<<<------+------->| unevictable lru |
  +-----+-----+                 |                             +-----------------+
        ^            FILE sync  v    ANON swap
        |            +----<<----+----->>---+
        |            |                     |
        |            v                     v
        |      +-----+-----+         +-----+-----+
        |      | page cache|         | swap cache|
        |      +-----+-----+         +-----+-----+
        |            |                     |
        |            |      reused page    |
        +----<<<-----+---------<<<---------+
                     v                     v
               +-----+-----+         +-----+-----+
               | file      |         | swap      |
               +-----+-----+         +-----+-----+
                     |                     |
                     +---->>----+----<<----+
                                |
                                v
                           +----+----+
                           |disk  dev|
                           +---------+
                           
  1. lru链表分类
type comments
LRU_INACTIVE_ANON 非活动的匿名映射页的lru
LRU_INACTIVE_FILE 非活动的文件映射页的lru
LRU_ACTIVE_ANON 活动的匿名映射页的lru
LRU_ACTIVE_FILE 活动的文件映射页的lru
LRU_UNEVICTABLE 不可回收页的lru
  1. lruper-CPU缓存分类
type comments

页高速缓存

数据结构

页高速缓存核心数据结构是address_space对象,被嵌入在页所有者的索引节点对象中。每个页描述符中使用mapping(索引节点的address_space对象)和index(页大小的磁盘镜像偏移)字段关联到页高速缓存中。

  1. 基树

struct radix_tree_root address_space.page_tree是基树的根,由深度、节点概念构成。每个节点可以存储64个槽位,如果是叶子节点则存储内容为页描述符,否则为其他的子树节点的指针。假设有页号为0、4、131三页数据,那么在树中的映射为:

                             +-------+
                             | h = 2 |
                             +-------+
                             | rnode |
                             +---+---+
                                 | 
                                 |
                                 v
                       +------------------+   
                       |   count = 2      |   
                       +------------------+   
                       | 0 | | 2 |...| 63 |   
                       +-+-----+----------+
                         |     |
                 +-------+     +-------+
                 |                     |
                 v                     v
         +------------------+  +------------------+    
         |   count = 2      |  |   count = 1      |    
         +------------------+  +------------------+    
         | 0 | | 4 |...| 63 |  | 0 | | 3 |...| 63 |    
         +-+-----+----------+  +-------+----------+ 
           |     |                     |
           |     +-------+             |
           |             |             |
           v             v             v
        +-----+       +-----+       +-----+
        |page |       |page |       |page |
        +-----+       +-----+       +-----+
  1. 优先搜索树

  2. 反向匿名映射

  3. 操作方法接口
    页高速缓存中的页通过const struct address_space_operations *a_ops操作对外部子系统提供操作,主要方法如下:

    • int (*writepage)(struct page *page, struct writeback_control *wbc) 写操作
    • int (*readpage)(struct file *, struct page *) 读操作
    • int (*write_begin)(struct file *, struct address_space *mapping, loff_t pos, unsigned len, unsigned flags, struct page **pagep, void **fsdata) 为写操作做准备
    • int (*write_end)(struct file *, struct address_space *mapping, loff_t pos, unsigned len, unsigned copied, struct page *page, void *fsdata) 完成写操作

内部操作API

API page comments
find_get_page() get_page() 根据偏移查找一页,然后增加页的引用
find_get_pages() get_page() 根据起始偏移和请求数量,查找一组连续的页,然后对每一页都增加引用
find_lock_page() 1. get_page()
2. lock_page()
根据偏移查找一页,然后增加页的引用,并试图锁定改页(可能发生阻塞)
add_to_page_cache_lru() 1. get_page()
2. __SetPageLocked()
3. page.mapping = mapping
4. page.index = offset
5. lru_cache_add()
1. 从外部分配新页。
2. 锁定页,因为是新页内容无效,防止其他的路径进行访问
3. 插入到页高速缓存中,并初始化页的高速缓存相关字段
4. 新缓存的可回收的页,插入lru
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值