DAMON-based Reclamation(DAMON_RECLAIM)是一个静态内核模块,旨在用于在轻度内存压力下主动和轻量级地回收内存。它不旨在取代基于LRU列表的页面粒度回收,而是选择性地用于不同级别的内存压力和需求。
何时需要主动回收?
在一般内存过度承诺的系统上,主动回收冷页面有助于节省内存,并减少由进程的直接回收或kswapd的CPU消耗引起的延迟峰值,同时只会带来最小的性能下降1 2。
基于基于Free Pages Reporting3的内存过度承诺虚拟化系统是一个很好的例子。在这种系统中,虚拟机将其空闲内存报告给主机,主机将报告的内存重新分配给其他虚拟机。结果,系统的内存被充分利用。然而,虚拟机可能并不节约内存,主要是因为一些内核子系统和用户空间应用程序被设计为尽可能多地使用可用内存。然后,虚拟机可能只向主机报告少量内存为空闲,导致系统的内存利用率下降。在虚拟机中运行主动回收可以缓解这个问题。
工作原理是什么?
DAMON_RECLAIM查找未在特定时间段内访问的内存区域,并进行页面交换。为了避免它在进行页面交换操作时消耗过多CPU,可以配置速度限制。在速度限制下,它首先对未访问时间较长的内存区域进行页面交换。系统管理员还可以配置在何种情况下该方案应自动激活和停用,以及三个内存压力水印。
接口:模块参数
要使用此功能,您首先应确保系统正在运行配置了 CONFIG_DAMON_RECLAIM=y 的内核。
为了让系统管理员启用或禁用它,并为给定系统进行调整,DAMON_RECLAIM利用模块参数。也就是说,您可以在内核引导命令行上放置 damon_reclaim.<parameter>=<value>
,或者将适当的值写入 /sys/module/damon_reclaim/parameters/<parameter>
文件。
以下是每个参数的描述。
- enabled
启用或禁用DAMON_RECLAIM。
您可以通过将此参数的值设置为Y来启用DAMON_RECLAIM,将其设置为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)配额的充值间隔。也就是说,DAMON_RECLAIM在quota_reset_interval_ms毫秒内不会尝试超过quota_ms毫秒或quota_sz字节的回收。
默认为1秒。 - 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