内核如何在磁盘缓存和交换之间做出决定?

Phi*_*ing 7 linux memory swap

继其他问题中提出的主题之后,我相信当 Linux 内核尝试释放物理 RAM 时,它会在丢弃磁盘缓存中的页面或将其他页面刷新到交换区之间做出某种决定。 我对此不确定,也许我完全误解了这个机制。

无论如何,以下方面之间存在协同作用:

  • 内核保留自己的内部磁盘缓存
  • 程序内存映射文件
  • “常规”应用程序内存被放置在交换文件中

所有这三个都可以用来释放物理 RAM,这三个都依赖于将“脏”页写入磁盘,或者只是知道这些页已经干净地复制到磁盘上并将它们从物理 RAM 分配中丢弃。


通过交换空间,可以为各个交换分区和文件赋予优先级,以便在较慢的设备之前使用较快的设备。我不知道其他非交换设备有任何此类配置。

我的问题是:内核如何决定释放哪些内存?

  • 它纯粹基于上次访问吗?
  • 内核是否同等地使用以上所有三个?
    • 它们(以及各个磁盘)之间是否有优先级
    • 可以配置吗?

这个问题是由与此类似的经历驱动的,但我希望这个问题重点关注底层机制,而不是解决特定问题。

Ste*_*itt 9

释放物理内存页的整个任务的名称是reclaim,它涵盖了许多任务。回收主要由页面分配驱动,具有不同的紧急程度。在卸载的系统上,可以毫不费力地满足页面分配,并且不会触发任何回收。在中等负载的系统上,页面分配仍然可以立即得到满足,但它们也会导致kswapd被唤醒以执行后台回收。在无法立即满足页面分配的已加载系统上,回收是同步执行的。

\n

可回收页面是存储可以在其他地方找到或可用的内容的页面。这就是典型的平衡行为发挥作用的地方:内容也在文件中的内存(或应该最终成为文件),v.内容不在文件中的内存(并且需要被换出)。前者存储在页面缓存中,后者则不存储,这就是为什么平衡解释通常谈论页面缓存与交换。

\n

优先选择其中一个的决定是在内核中的一个位置 确定的,get_scan_count由 中的设置控制struct scan_control。该函数\xe2\x80\x99的用途描述如下:

\n
\n

确定扫描匿名和文件 LRU 列表的积极程度。\n 每组 LRU 列表的相对值是通过查看我们确实旋转回活动列表而不是逐出的扫描页面的比例来确定的。

\n
\n

也许令人惊讶的是,对于名为 的函数get_...,它\xe2\x80\x99 不使用返回值;相反,它填充指针指向的数组unsigned long *nr,其中四个条目对应于匿名非活动页面(未支持、最近未使用的页面)、匿名活动页面(未支持、最近使用的页面)、文件非活动页面(页面缓存中最近未使用的页面)和文件活动页面(页面缓存中最近使用的页面)。

\n

get_scan_count首先从 中检索适当的 \xe2\x80\x9cswappiness\xe2\x80\x9d 值mem_cgroup_swappiness。如果当前内存 cgroup 是已启用的非 root v1 cgroup,则使用其交换设置;否则,它\xe2\x80\x99就是臭名昭著的/proc/sys/vm/swappiness. 两种设置具有相同的目的;他们告诉内核

\n
\n

带回换出的匿名页面与重新加载文件系统页面的相对 IO 成本

\n
\n

但在实际使用该值之前,get_scan_count请确定应应用的总体策略:

\n
    \n
  • 如果\xe2\x80\x99s没有交换,或者匿名页面不能在当前上下文中回收\xe2\x80\x99,则它将仅处理文件支持的页面;
  • \n
  • 如果内存 cgroup 完全禁用交换,它将仅处理文件支持的页面;
  • \n
  • 如果 swappiness 被\xe2\x80\x99t 禁用(设置为 0),并且系统内存即将耗尽,它将平等地处理所有页面;
  • \n
  • 如果系统几乎用完文件页面,它将仅处理匿名页面;
  • \n
  • 如果有足够的非活动页面缓存,它将仅查找文件支持的页面;
  • \n
  • 在所有其他情况下,它根据相应的 I/O 成本调整给予各个 LRU 的 \xe2\x80\x9cweight\xe2\x80\x9d 。
  • \n
\n

一旦确定了策略,它就会迭代所有可逐出的 LRU(按顺序非活动匿名、活动匿名、非活动文件支持、活动文件支持)以确定应扫描每个 LRU 的页数;I\xe2\x80\x99ll 忽略 v1 cgroup:

\n
    \n
  • 如果策略是 \xe2\x80\x9cgo 在所有页之后均等\xe2\x80\x9d,则所有 LRU 中的所有页都容易被扫描,最大大小由scan_control\xe2\x80\x99spriority移位因子确定;
  • \n
  • 如果策略是 \xe2\x80\x9cgo 仅在文件支持的页面之后\xe2\x80\x9d 或 \xe2\x80\x9cgo 仅在匿名页面之后\xe2\x80\x9d,则相应 LRU 中的所有页面都是候选页面(同样) ,移位priority),其他 LRU 中没有;
  • \n
  • 否则,根据交换性调整值。
  • \n
\n

实际的页面扫描由 驱动shrink_lruvec,它使用上面确定的扫描长度,并重复收缩LRU,直到达到目标(以各种方式调整目标)。完成此操作后,活动/非活动 LRU 将重新平衡。

\n

回到你的问题:

\n
    \n
  • 页缓存和内存映射文件受到同等对待;
  • \n
  • 页面回收\xe2\x80\x99t纯粹基于上次访问(我没有\xe2\x80\x99t解释了LRU是如何使用的,或者重新平衡是如何工作的;阅读Mel Gorman\xe2\x80\x99s中的相应章节了解Linux 虚拟内存管理器了解详细信息);
  • \n
  • 内核不\xe2\x80\x99同等地使用它们;它们根据情况划分不同的优先级,并且可以通过许多控件(swappiness、cgroup、低水位阈值...)进行配置。
  • \n
\n

交换优先级仅决定页面在决定将其交换出后的位置。(顺便说一句,swappiness上面的文档和解释应该清楚地表明,I/O 成本没有足够的粒度来很好地处理混合 ZRAM/磁盘交换设置......)

\n

还有很多需要解释,包括如何scan_control设置,但我怀疑这已经太长了!如果您想跟踪回收成本,您可以在任务延迟核算中查看它(另请参阅struct taskstats)。

\n

  • 这是关于这个主题的精彩入门读物。我会花一些时间消化您推荐的进一步阅读。我特别欣赏对“交换性”如何适应这张图片的更详细的解释。感谢您花费宝贵的时间来整理它! (2认同)