继其他问题中提出的主题之后,我相信当 Linux 内核试图释放物理 RAM 时,它会在从磁盘缓存中丢弃页面或将其他页面刷新到交换中做出某种决定。 我不确定这一点,也许我完全误解了机制。
无论如何,两者之间存在协同作用:
- 内核保持它自己的内部磁盘缓存
- 程序内存映射文件
- “常规”应用程序内存被放置在交换文件中
这三个都可以用来释放物理 RAM,这三个都依赖于将“脏”页面写入磁盘,或者只是知道这些页面已经在磁盘上完全复制并从物理 RAM 分配中丢弃它们。
使用交换空间,可以为各个交换分区和文件赋予优先级,以便在使用较慢设备之前使用较快的设备。我不知道其他非交换设备的任何此类配置。
我的问题是:内核如何决定要释放哪些 RAM?
- 它纯粹基于最后一次访问吗?
- 内核是否平等地使用上述所有三个?
- 它们(和单个磁盘)之间是否有任何优先级
- 它是可配置的吗?
这个问题由与此类似的经验驱动,但我希望这个问题关注底层机制而不是解决特定问题。
释放物理内存页的整个任务的名称是回收,它涵盖了许多任务。回收主要由页面分配驱动,具有不同程度的紧迫性。在卸载的系统上,页面分配可以毫不费力地得到满足,并且不会触发任何回收。在中等负载的系统上,仍然可以立即满足页面分配,但它们也会导致
kswapd
被唤醒以执行后台回收。在无法立即满足页面分配的已加载系统上,同步执行回收。可回收页面是存储可以在其他地方找到或可用的内容的页面。这就是典型的平衡行为发挥作用的地方:内容也在文件中(或应该以文件结尾)的内存,v. 内容不在的内存(并且需要换出)。前者存储在页面缓存中,后者不存储,这就是为什么平衡解释通常谈论页面缓存与交换。
在内核中的一个位置确定优先于另一个的决定,
get_scan_count
由 中的设置控制struct scan_control
。该函数的目的描述如下:对于名为 的函数
get_...
,这可能令人惊讶,它不使用返回值;相反,它填充unsigned long *nr
指针指向的数组,其中四个条目对应于匿名非活动页面(未支持,最近未使用的页面),匿名活动页面(未支持,最近使用的页面),文件不活动页面(页面缓存中最近未使用的页面)和文件活动页面(页面缓存中最近使用的页面)。get_scan_count
首先从 检索适当的“swappiness”值mem_cgroup_swappiness
。如果当前内存 cgroup 是已启用的非 root v1 cgroup,则使用其 swappiness 设置;否则,就是臭名昭著的/proc/sys/vm/swappiness
。两种设置的目的相同;他们告诉内核在它实际使用这个值之前,
get_scan_count
确定它应该应用的整体策略:一旦确定了策略,它就会遍历所有可驱逐的 LRU(按顺序为非活动匿名、活动匿名、非活动文件支持、活动文件支持)以确定应该扫描每个 LRU 的多少页;我将忽略 v1 cgroups:
scan_control
的priority
移位因子确定的大小;priority
),其他 LRU 中没有;实际的页面扫描由 驱动
shrink_lruvec
,它使用上面确定的扫描长度,并反复收缩LRU,直到达到目标(以各种方式调整目标)。完成此操作后,将重新平衡活动/非活动 LRU。回到你的问题:
swappiness
、cgroups、低水位阈值...)进行配置。交换优先级仅确定页面在决定将其换出后的去向。(顺便说一下,
swappiness
上面的文档和解释应该清楚地表明,I/O 成本没有足够的粒度来很好地处理混合 ZRAM/磁盘交换设置......)还有很多要解释的,包括如何
scan_control
设置,但我怀疑这已经太长了!如果您想跟踪回收成本,您可以在任务延迟会计中看到它(另请参阅struct taskstats
)。