基于DAMON的回收

基于DAMON的回收(DAMON_RECLAIM)是一个静态内核模块,旨在用于在轻微内存压力下的主动和轻量级回收。它并非旨在取代基于LRU列表的页面粒度回收,而是选择性地用于不同级别的内存压力和要求。

哪里需要主动回收?

在一般的内存过度提交系统上,主动回收冷页面有助于节省内存,并减少由进程直接回收或kswapd的CPU消耗引起的延迟峰值,同时仅造成最小的性能下降 [1] [2]

基于自由页面报告 [3] 的内存过度提交虚拟化系统是这些情况的良好示例。在这样的系统中,客户虚拟机将其空闲内存报告给主机,并且主机将报告的内存重新分配给其他客户虚拟机。结果,系统的内存得到充分利用。但是,客户虚拟机可能不是那么节约内存,主要是因为某些内核子系统和用户空间应用程序被设计为尽可能多地使用可用内存。然后,客户虚拟机可能仅向主机报告少量内存为空闲,从而导致系统内存利用率下降。在客户虚拟机中运行主动回收可以缓解此问题。

它是如何工作的?

DAMON_RECLAIM查找在特定时间段内未被访问的内存区域并将其换出。为了避免它在换出操作中消耗过多CPU,可以配置速度限制。在速度限制下,它首先换出未被访问较长时间的内存区域。系统管理员还可以配置在什么情况下应使用三个内存压力水位线自动激活和停用此方案。

接口:模块参数

要使用此功能,您首先应确保您的系统正在运行使用 CONFIG_DAMON_RECLAIM=y 构建的内核。

为了使系统管理员能够启用或禁用它并针对给定系统进行调整,DAMON_RECLAIM利用模块参数。也就是说,您可以在内核启动命令行上放置 damon_reclaim.<参数>=<值> 或将适当的值写入 /sys/module/damon_reclaim/parameters/<参数> 文件。

以下是每个参数的描述。

enabled

启用或禁用DAMON_RECLAIM。

您可以通过将此参数的值设置为 Y 来启用DAMON_RCLAIM。将其设置为 N 将禁用DAMON_RECLAIM。请注意,由于基于水位线的激活条件,DAMON_RECLAIM可能无法进行真正的监视和回收。有关此内容的更多信息,请参阅以下关于水位线参数的描述。

commit_inputs

使DAMON_RECLAIM再次读取输入参数,除了 enabled

默认情况下,在DAMON_RECLAIM运行时更新的输入参数不会应用。一旦此参数设置为 Y,DAMON_RECLAIM将再次读取参数的值,除了 enabled。重新读取完成后,此参数将设置为 N。如果在重新读取时发现无效参数,则将禁用DAMON_RECLAIM。

min_age

用于冷内存区域识别的时间阈值,以微秒为单位。

如果内存区域在此时间或更长时间内未被访问,则DAMON_RECLAIM会将该区域标识为冷区域,并对其进行回收。

默认情况下为120秒。

quota_ms

以毫秒为单位的回收时间限制。

DAMON_RECLAIM尝试在时间窗口 (quota_reset_interval_ms) 内仅使用不超过此时间来尝试回收冷页面。这可以用于限制DAMON_RECLAIM的CPU消耗。如果该值为零,则禁用该限制。

默认情况下为10毫秒。

quota_sz

以字节为单位的回收内存大小限制。

DAMON_RECLAIM会计算它在时间窗口 (quota_reset_interval_ms) 内尝试回收的内存量,并且尝试回收的内存不会超过此限制。这可以用于限制CPU和IO的消耗。如果此值为零,则禁用该限制。

默认情况下为128 MiB。

quota_reset_interval_ms

时间/大小配额充电重置间隔,以毫秒为单位。

时间(quota_ms)和大小(quota_sz)配额的充电重置间隔。也就是说,在quota_reset_interval_ms毫秒内,DAMON_RECLAIM不会尝试回收超过quota_ms毫秒或quota_sz字节的内存。

默认情况下为1秒。

quota_mem_pressure_us

以微秒为单位的期望的内存压力-暂停时间级别。

在保持其他配额设置的上限的同时,DAMON_RECLAIM会自动增加和减少有效配额级别,以达到此级别的内存压力。收集系统范围内每个配额重置间隔 ( quota_reset_interval_ms) 以微秒为单位的 some 内存PSI,并将其与此值进行比较,以查看是否满足目标。值零表示禁用此自动调整功能。

默认情况下禁用。

quota_autotune_feedback

用户可指定的有效配额自动调整反馈。

在保持其他配额设置的上限的同时,DAMON_RECLAIM会自动增加和减少有效配额级别,以达到从用户处收到值为 10,000 的此反馈。DAMON_RECLAIM假定反馈值和配额成正比。值零表示禁用此自动调整功能。

默认情况下禁用。

wmarks_interval

当启用DAMON_RECLAIM但由于其水位线规则而处于非活动状态时,在检查水位线之前要等待的最短时间。

wmarks_high

高水位线的可用内存率(每千分之几)。

如果系统每千字节的可用内存量高于此值,则DAMON_RECLAIM变为非活动状态,因此它不执行任何操作,而仅定期检查水位线。

wmarks_mid

中间水位线的可用内存率(每千分之几)。

如果系统每千字节的可用内存量介于此值和低水位线之间,则DAMON_RECLAIM变为活动状态,因此启动监视和回收。

wmarks_low

低水位线的可用内存率(每千分之几)。

如果系统每千字节的可用内存量低于此值,则DAMON_RECLAIM变为非活动状态,因此它不执行任何操作,而仅定期检查水位线。在这种情况下,系统将回退到基于LRU列表的页面粒度回收逻辑。

sample_interval

用于监控的采样间隔,单位为微秒。

DAMON 用于冷内存监控的采样间隔。请参考 DAMON 文档 (详细用法) 获取更多详细信息。

aggr_interval

用于监控的聚合间隔,单位为微秒。

DAMON 用于冷内存监控的聚合间隔。请参考 DAMON 文档 (详细用法) 获取更多详细信息。

min_nr_regions

监控区域的最小数量。

DAMON 用于冷内存监控的监控区域的最小数量。这可以用于设置监控质量的下限。但是,设置得太高可能会导致监控开销增加。请参考 DAMON 文档 (详细用法) 获取更多详细信息。

max_nr_regions

监控区域的最大数量。

DAMON 用于冷内存监控的监控区域的最大数量。这可以用于设置监控开销的上限。但是,设置得太低可能会导致监控质量不佳。请参考 DAMON 文档 (详细用法) 获取更多详细信息。

monitor_region_start

目标内存区域的起始物理地址。

DAMON_RECLAIM 将针对其工作的内存区域的起始物理地址。也就是说,DAMON_RECLAIM 将在此区域中查找冷内存区域并进行回收。默认情况下,最大的系统 RAM 用作该区域。

monitor_region_end

目标内存区域的结束物理地址。

DAMON_RECLAIM 将针对其工作的内存区域的结束物理地址。也就是说,DAMON_RECLAIM 将在此区域中查找冷内存区域并进行回收。默认情况下,最大的系统 RAM 用作该区域。

skip_anon

跳过匿名页面的回收。

如果此参数设置为 Y,则 DAMON_RECLAIM 不回收匿名页面。默认情况下为 N

kdamond_pid

DAMON 线程的 PID。

如果启用 DAMON_RECLAIM,则此为工作线程的 PID。否则为 -1。

nr_reclaim_tried_regions

DAMON_RECLAIM 尝试回收的内存区域数量。

bytes_reclaim_tried_regions

DAMON_RECLAIM 尝试回收的内存区域的总字节数。

nr_reclaimed_regions

DAMON_RECLAIM 成功回收的内存区域数量。

bytes_reclaimed_regions

DAMON_RECLAIM 成功回收的内存区域的总字节数。

nr_quota_exceeds

超出时间/空间配额限制的次数。

示例

以下运行时示例命令使 DAMON_RECLAIM 查找 30 秒或更长时间未访问的内存区域并将其换出。回收操作限制为每秒最多 1 GiB,以避免 DAMON_RECLAIM 为换出操作消耗过多 CPU 时间。它还要求,如果系统的空闲内存率高于 50%,则 DAMON_RECLAIM 不执行任何操作,但如果空闲内存率低于 40%,则开始执行实际操作。如果 DAMON_RECLAIM 没有取得进展,因此空闲内存率低于 20%,它会再次要求 DAMON_RECLAIM 不执行任何操作,以便我们可以退回到基于 LRU 列表的页面粒度回收。

# cd /sys/module/damon_reclaim/parameters
# echo 30000000 > min_age
# echo $((1 * 1024 * 1024 * 1024)) > quota_sz
# echo 1000 > quota_reset_interval_ms
# echo 500 > wmarks_high
# echo 400 > wmarks_mid
# echo 200 > wmarks_low
# echo Y > enabled