sou*_*edi 13 linux memory swap
假设一个程序需要一些内存,但没有足够的可用内存。Linux 有几种不同的响应方式。一种响应是选择一些最近没有被访问过的其他已用内存,并将这个不活动的内存移动到交换区。
但是,我看到很多文章和评论都超出了这个范围。他们说即使有大量空闲内存,Linux 有时也会决定写入非活动内存进行交换。提前写入交换意味着当我们最终想要使用这块内存时,我们不必等待磁盘写入。他们说这是一种优化性能的深思熟虑的策略。
他们是对的吗?或者这是一个神话?引用您的来源。
请使用以下定义理解这个问题:
MemFree
来自的值/proc/meminfo
。 /proc/meminfo
是内核提供的虚拟文本文件。请参阅proc(5)或RHEL 文档。这里有一些搜索词:linux“机会交换”或(交换“当系统无事可做时”或“当它无事可做时”或“系统空闲时”或“空闲时间”)
在 Google 上排名第二的结果中,StackExchange 用户询问“当 RAM 中有足够多的可用空间时为什么要使用交换?”,并复制free
显示大约 20% 可用内存的命令的结果。在回答这个特定问题时,我看到这个答案得到了高度评价:
Linux 在 RAM 被填满之前开始交换。这样做是为了提高性能和响应能力:
性能提高是因为有时 RAM 更适合用于磁盘缓存而不是存储程序内存。因此,最好将一段时间不活动的程序换掉,而将经常使用的文件保存在缓存中。
通过在系统空闲时换出页面来提高响应能力,而不是在内存已满且某些程序正在运行并请求更多 RAM 来完成任务时。
当然,交换确实会降低系统速度——但交换的替代方案并不是不交换,而是拥有更多的 RAM 或使用更少的 RAM。
谷歌上的第一个结果已被标记为上述问题的重复:-)。在这种情况下,提问者复制了显示 7GB 的详细信息MemFree
,共 16GB。这个问题有一个自己接受和赞成的答案:
仅当没有空闲内存时才交换,只有设置
swappiness
为 0时才如此。否则,在空闲时间,内核将交换内存。这样做时,数据不会从内存中删除,而是在交换分区中进行复制。这意味着,如果出现内存耗尽的情况,则不必立即写入磁盘。在这种情况下,内核可以只覆盖已经交换的内存页面,它知道它有数据的副本。
该
swappiness
参数基本上只是控制它执行此操作的程度。
另一个引用没有明确声明交换的数据也保留在内存中。但似乎您更喜欢这种方法,如果您即使在有 20% 的空闲内存时也进行交换,并且您这样做的原因是为了提高性能。
据我所知,Linux 确实支持在主内存和交换空间中保留相同数据的副本。
我还注意到“机会交换”发生在“空闲时间”的普遍说法。我知道它应该有助于让我确信此功能通常对性能有益。我没有在上面的定义中包含这个,因为我认为它已经有足够的细节来提出一个很好的明确问题。我不想让这变得比需要的更复杂。
当我有千兆字节的空闲内存时,atop 会显示 `swout`(交换)。为什么?
有几个这样的报告,当有足够的空闲内存时,Linux 写入交换。“机会主义交换”可以解释这些报告。同时,至少提出了一个替代原因。作为查看可能原因的第一步:Linux 是否执行过上述定义的“机会交换”?
在我报告的例子中,现在已经回答了这个问题。原因不是机会主义的交换。
sou*_*edi 15
Linux 不执行此问题中定义的“机会交换”。
以下主要参考文献根本没有提到这个概念:
进一步来说:
过去
kswapd
每 10 秒唤醒一次,但现在只有当达到区域中的 pages_low 空闲页面数时,物理页面分配器才会唤醒它。[...] 在极端内存压力下,进程会kswapd
同步完成工作。[...]kswapd
不断释放页面,直到达到 pages_high 水印。
基于上述,当空闲页数高于“高水印”时,我们不会期望任何交换。
其次,这告诉我们这样做的目的kswapd
是为了制作更多的免费页面。
当kswapd
写入要交换的内存页时,它会立即释放内存页。 kswapd 不会在内存中保留交换页面的副本。
Linux 2.6 使用“ rmap ”来释放页面。在 Linux 2.4 中,情况更加复杂。当一个页面被多个进程共享时,kswapd 无法立即释放它。这是古老的历史。所有链接的帖子都是关于 Linux 2.6 或更高版本的。
此控件用于定义内核交换内存页面的积极程度。较高的值会增加攻击性,较低的值会减少交换量。值 0 指示内核在空闲和文件支持的页面数量小于区域中的高水位线之前不启动交换。
这句话描述了一种特殊情况:如果您将swappiness
值配置为0
. 在这种情况下,我们不应该期待任何交换,直到缓存页面的数量下降到高水位线。换句话说,内核会在开始交换之前尝试丢弃几乎所有的文件缓存。(这可能会导致大量减速。您需要有一些文件缓存!文件缓存用于保存所有正在运行的程序的代码:-)
以上引用提出了一个问题:我系统上的“水印”内存预留有多大?答:在“小型”系统上,默认区域水印可能高达内存的 3%。这是由于“最小”水印的计算。在较大的系统上,水印的比例较小,接近内存的 0.3%。
因此,如果问题是关于空闲内存超过 10% 的系统,则此水印逻辑的确切细节并不重要。
每个单独“区域”的水印显示在 中/proc/zoneinfo
,如proc(5) 中所述。摘自我的 zoneinfo:
Node 0, zone DMA32
pages free 304988
min 7250
low 9062
high 10874
spanned 1044480
present 888973
managed 872457
protection: (0, 0, 4424, 4424, 4424)
...
Node 0, zone Normal
pages free 11977
min 9611
low 12013
high 14415
spanned 1173504
present 1173504
managed 1134236
protection: (0, 0, 0, 0, 0)
Run Code Online (Sandbox Code Playgroud)
目前的“水印”是min
,low
和high
。如果一个程序曾经要求足够的内存来减少free
以下内容min
,该程序将进入“直接回收”。当内核释放内存时,程序会等待。
如果可能,我们希望避免直接回收。因此,如果free
低于low
水印,内核就会唤醒kswapd
。 kswapd
通过交换和/或删除缓存来释放内存,直到再次free
高于high
。
附加限定:kswapd
还将运行以保护全部 lowmem_reserve 量,用于内核 lowmem 和 DMA 使用。默认的lowmem_reserve大约是第一个 4GiB RAM(DMA32 区域)的 1/256,因此通常在 16MiB 左右。
[...]
watermark_scale_factor:
这个因素控制了 kswapd 的攻击性。它定义了在 kswapd 被唤醒之前节点/系统中剩余的内存量以及在 kswapd 返回睡眠之前需要释放多少内存。
单位是 10,000 的分数。默认值 10 表示水印之间的距离是节点/系统中可用内存的 0.1%。最大值为 1000,即内存的 10%。
线程进入直接回收(allocstall)或 kswapd 过早休眠(kswapd_low_wmark_hit_quickly)的高比率可能表明 kswapd 由于延迟原因维护的空闲页面数量对于系统中发生的分配突发来说太小。然后可以使用此旋钮相应地调整 kswapd 的积极性。
中的
MemAvailable
项目/proc/meminfo
是向用户提示可分配多少内存而不引起交换,因此它将区域的低水印排除为用户空间不可用。然而,对于用户空间分配,
kswapd
实际上会回收,直到空闲页面达到高水位线和页面分配器的低内存保护的组合,该保护也从用户空间保留一定数量的 DMA 和 DMA32 内存。在计算 MemAvailable 时,从可用页面数中减去我们知道用户空间不可用的全部数量。
有时声称更改swappiness
为0
将有效禁用“机会交换”。这提供了一个有趣的调查途径。如果有一种叫做“机会交换”的东西,并且它可以通过交换来调整,那么我们可以通过找到所有读取vm_swappiness
. 请注意,我们可以通过假设CONFIG_MEMCG
未设置来减少搜索空间(即“内存 cgroups”已禁用)。调用链如下:
shrink_node_memcg
评论“这是一个基本的每节点页面释放器。由 kswapd 和直接回收使用”。即这个功能增加了空闲页面的数量。它不会尝试复制要交换的页面,以便在以后释放它们。但即使我们打折扣:
上面的链是从三个不同的函数调用的,如下所示。正如预期的那样,我们可以将调用站点分为直接回收和 kswapd。在直接回收中执行“机会主义交换”是没有意义的。
/* * 这是直接回收路径,用于页面分配进程。只有我们 * 尝试从区域回收页面以满足调用者的分配 * 要求。 * *如果一个区域被认为充满了固定页面,那么就给它一个灯 *扫描然后放弃它。 */ 静态无效收缩区域
* kswapd 收缩处于或低于最高可用值的页面节点 * 当前不平衡的区域。 * * 如果 kswapd 至少扫描了请求的页数,则返回 true * 回收或者如果由于页面写回而导致进度不足。 * 用于确定是否需要提高扫描优先级。 */ static bool kswapd_shrink_node
* 对于 kswapd,balance_pgdat() 将从区域中跨节点回收页面 * 有资格供呼叫者使用,直到至少一个区域被 * 平衡。 * * 返回 kswapd 完成回收的顺序。 * * kswapd 在 highmem->normal->dma 方向扫描区域。它跳过 * 具有 free_pages > high_wmark_pages(zone) 的区域,但是一旦一个区域被 * 发现有 free_pages <= high_wmark_pages(zone),该区域中的任何页面 * 或更低有资格回收,直到至少一个可用区域被 * 平衡。 */ 静态 int balance_pgdat
因此,大概声称 kswapd 以某种方式被唤醒,即使所有内存分配都立即从空闲内存中得到满足。我查看了 的使用wake_up_interruptible(&pgdat->kswapd_wait)
,我没有看到任何像这样的唤醒。
不,Linux 中没有机会交换这样的东西。我花了一些时间研究这个问题,所有的来源(教科书、内核开发人员邮件列表上的电子邮件、Linux 源代码和提交评论,以及与 Mel Gorman 的一些 Twitter 交流)都告诉我同样的事情:Linux 只回收内存以响应某种形式的内存压力(明显的休眠除外)。
关于这个主题的所有流行的误解可能源于一个简单的事实,即 Linux 不能等到空闲内存的最后一个字节才开始交换。它需要某种缓冲来保护它免受极端形式的内存耗尽的影响,并且有一些可调参数可以影响该缓冲的大小(例如vm.min_free_kbytes
)。但这与“因为无事可做而交换”不同。
不幸的是,相对于 2.6(在 Mel Gorman 的书中详细描述了它),页框回收算法变得更加复杂,但基本思想或多或少是相同的:页面回收由失败的分配触发,然后kswapd
同步唤醒或尝试释放页面(取决于内存压力、分配标志和其他因素)。
页面分配可能在剩余足够空闲内存的情况下开始失败的最明显原因是它们可能要求连续内存,而实际上内存可能过于分散而无法满足请求。从历史上看,Linux 内核开发人员竭尽全力避免对连续分配的需求。尽管如此,一些设备驱动程序仍然需要这样做——要么是因为它们不能进行多页内存 I/O(分散-聚集 DMA),要么可能只是驱动程序开发人员的草率编码。Transparent Huge Pages (THP) 的出现为在物理上连续的块中分配内存提供了另一个原因。
大约在同一时间范围内引入的区域压缩应该有助于解决内存碎片问题,但它并不总是产生预期的效果。
有各种vmscan
跟踪点可以帮助了解在您的特定情况下到底发生了什么——当具有特定的调用堆栈时,在 Linux 内核代码中找到您需要的东西总是更容易,而不是仅仅扫描看起来远程相关的所有内容。
归档时间: |
|
查看次数: |
2007 次 |
最近记录: |