> For the complete documentation index, see [llms.txt](https://richardweiyang-2.gitbook.io/kernel-exploring/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://richardweiyang-2.gitbook.io/kernel-exploring/nei-cun-guan-li/00-index-1/06_reclaim_core.md).

# 回收的核心逻辑

## 回收的大致逻辑

下面整理了一下回收中个人认为比较重要的调用关系。

* 左边从kswapd()开始的是间接回收
* 中间从node\_reclaim()开始的是直接回收（省略了其他的部分）
* 最右边是memcg对内存的限制（猜测）

```
kswapd() // one thread for each node
    |
    v
balace_pgdat(pgdat, )                node_reclaim()
    |                                    |
    v                                    v
kswapd_shrink_node(pgdat, )          __node_reclaim(pgdat, )
    \                                      /
         \                            /
              \                  /
                   \        /
                        v
                 shrink_node(pgdat, )                           mem_cgroup_soft_reclaim()
                     |                                                |
                     v                                                v
                 shrink_node_memcgs(pgdat, )                    mem_cgroup_shrink_node(memcg, )
                     memcg = mem_cgroup_iter()                      lruvec = mem_cgroup_lruvec(memcg, pgdat)
                     lruvec = mem_cgroup_lruvec(memcg, pgdat)

                             \                                      /
                                  \                            /
                                       \                  /
                                            \        /
                                                 v
                                         shrink_lruvec(lruvec, )
                                                 |
                                                 v
                                           shrink_list(lruvec, )
                                                 ^
                                            /          \
                                       /                    \
                                  /                              \
                       shrink_active_list()               shrink_inactive_list()
                                                                 |
                                                                 |
                                                                 v
                                                          shrink_folio_list(&folio_list, )
                                                                 |
                                                                 |
                                                                 v
                                                              pageout()
```

但是不管怎么样的路径下来，最后都是走到了shrink\_lruvec(lruvec,)，那自然他就是我们重点观照对象。

并且从名字上看出，我们回收内存时管理的最小对象是lruvec。

## priority

priority是一个整型，语义上表示重要程度：值越小，优先级越高。

数值上表示，每次回收过程中扫描(total\_pages >> priority)数量的页。所以数值越小，优先级越高，扫描的页面越多。

## swappiness

swappiness是一个可以调节的参数，/proc/sys/vm/swappiness，表示在文件页和匿名页之间更倾向于回收哪种。

这个的作用在get\_scan\_count()->calculate\_pressure\_balance()中体现。

我们可以分别将swappiness为0和MAX\_SWAPPINESS代入，得到ap是0,或者fp是0。表明

* swappiness = 0: 只回收文件页
* swappiness = MAX\_SWAP: 只回收匿名页

## shrink\_list

在shrink\_lruvec()中，通过get\_scan\_count()和其他逻辑计算出了各链表上需要扫表的数量后，就通过shrink\_list()来做扫描。

* shrink\_active\_list: 扫描活跃链表，从链表尾部开始扫描，将合适的页面移动到inactive list
* shrink\_inactive\_list: 扫描不活跃链表，合适的时候通过shrink\_folio\_list()回收
