当我有千兆字节的可用内存时,顶部显示“swout”(交换)。为什么?

当我有千兆字节的可用内存时,顶部显示“swout”(交换)。为什么?

当我有千兆字节的可用内存时,为什么atop显示我正在交换超过 20,000 个页面(超过 80 兆字节)?

我没有注意到这有性能问题。我只是想借此机会增加我的知识:-)。

atop每十秒刷新一次。每次刷新都会显示自上次刷新以来的活动。

MEM | tot     7.7G | free    3.7G | cache 608.3M | buff   19.1M | slab  264.6M |
SWP | tot     2.0G | free    1.4G |              | vmcom  13.4G | vmlim   5.8G |
PAG | scan  167264 | steal 109112 | stall      0 | swin       0 | swout  23834 |

                                "swout" is non-zero and coloured in red  ^

内核内存信息:

$ head -n 5 /proc/meminfo
MemTotal:        8042664 kB
MemFree:         3563088 kB
MemAvailable:    3922092 kB
Buffers:           20484 kB
Cached:           775308 kB

内核版本:

$ uname -r
5.0.16-200.fc29.x86_64

  1. 目前尚不清楚这是否会受到影响vm.swappiness。该设置平衡了缓存回收与交换。然而有很多自由的内存,那么为什么我们首先需要回收内存呢?

  2. 正如您所看到的,这是一个小系统。它不使用 NUMA。我签入/proc/zoneinfo后发现只有一个节点“Node 0”。所以这不是由 NUMA 引起

  3. 相关问题和答案提到了“机会主义交换”、“当系统无事可做时”、“如果以后出现内存短缺,这可能会带来好处”等想法。我认为这些想法不可信,因为它们与内核文档相矛盾。看 Linux 是否执行“机会主义交换”,还是一个神话?

  4. 使用功能时对 RAM 使用没有设置限制systemd.resources。即我认为所有systemd设备的 RAM 使用限制都设置为“无限”。

    $ systemctl show '*' | \
        grep -E '(Memory|Swap).*(Max|Limit|High)' | \
        grep -v infinity
    $
    
  5. 编辑:我怀疑这与透明大页面有关。我注意到虚拟机使用透明大页面来有效地分配来宾内存。它们是唯一使用大页面的用户程序在我的系统上

    有一个类似的问题:如果可用内存远超过pages_high水位线,kswapd可以激活吗?它询问的是 RHEL 6,它为所有应用程序启用大页面。

我不确定如何重现这个结果。

启动虚拟机时发生这种情况。我使用 libvirt 来运行虚拟机。默认情况下,VM 磁盘读取使用主机页面缓存进行缓存。 (缓存模式:“Hypervisor 默认”表示“写回”)。

我尝试停止虚拟机、FADVISE_DONTNEED映像文件,然后重试。但同样的事情并没有发生。

然后我再次尝试使用不同的虚拟机,并且这种情况发生了很短的时间。我捕捉到了vmstat。我认为atop“swout”显示了一个不同的、更高的数字,但我没有捕捉到它。

$ vmstat 10
procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
 r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
 0  0 770168 5034300  28024 936256    0    2    21    86   60  101 22  9 68  1  0
 0  0 770168 5033852  28048 935904    0    0     0     8  372  633  1  1 97  0  0
 1  0 770168 4974048  28252 948152    3    0  1137   194 1859 2559 11  7 79  3  0
 0  1 770168 4557968  28308 1037512    0    0  8974    45 3595 6218 16  6 57 21  0
 6  3 770168 4317800  28324 1111408    0    0  7200   609 6820 6793 12  5 38 44  0
 0  4 770168 4125100  28348 1182624    0    0  6900   269 5054 3674 74  3  8 15  0
 0  5 770168 3898200  27840 1259768    2    0  9421   630 4694 5465 11  6 11 71  0
 1  3 770168 3760316  27672 1300540    0    0  9294   897 3308 4135  5  4 28 63  0
 0  1 770168 3531332  27032 1356236    0    0 10532   155 3140 4949  8  5 63 25  0
 0  0 783772 3381556  27032 1320296    0 1390  7320  4210 4450 5112 17  5 43 35  0
 0  0 783772 3446284  27056 1335116    0    0   239   441  995 1782  4  2 92  2  0
 0  0 783772 3459688  27076 1335372    0    0     3   410  728 1037  2  2 95  1  0

我还检查了虚拟机上的 cgroup 内存限制,以防 libvirt 绕过systemd并错误地对自身造成交换:

$ cd /sys/fs/cgroup/memory/machine.slice/machine-qemu\x2d5\x2ddebian9.scope
$ find -type d  # there were no sub-directories here
$ grep -H . *limit_in_bytes
memory.kmem.limit_in_bytes:9223372036854771712
memory.kmem.tcp.limit_in_bytes:9223372036854771712
memory.limit_in_bytes:9223372036854771712
memory.memsw.limit_in_bytes:9223372036854771712
memory.soft_limit_in_bytes:9223372036854771712
$ cd ../..
$ find -name "*limit_in_bytes" -exec grep -H -v 9223372036854771712 \{\} \;
$

答案1

我正在思考一个类似的问题——你看到了我关于 kswapd 和区域水印的帖子——我的例子(也可能在你的例子中)的答案是内存碎片。

当内存碎片足够多时,高阶分配将失败,这(取决于许多其他因素)将导致直接回收,或者将唤醒 kswapd,它将尝试进行区域回收/压缩。您可以在我的帖子中找到一些其他详细信息。

处理此类问题时可能被忽视的另一件事是记忆分区。即你可能有足够的内存全面的(它甚至可能包含足够的连续块)但它可能仅限于 DMA32(如果您使用 64 位架构)。有些人倾向于忽略 DMA32,认为它“小”(可能是因为他们习惯了 32 位思维),但 4GB 并不是真正的“小”。

您有两种方法可以确定您的案例中发生了什么。一是分析统计数据——您可以设置作业来定期拍摄 /proc/buddyinfo、/proc/zoneinfo、/proc/vmstat 等快照,并尝试理解您所看到的内容。

如果您让它工作,另一种方法会更直接和可靠:您需要捕获导致交换事件的代码路径,并且您可以使用内核检测的跟踪点来完成此操作(特别是,有许多 vmscan 事件)。

但让它发挥作用可能具有挑战性,因为低级仪器并不总是按照开箱即用的方式工作。就我而言,我们不得不花费一些时间来设置 ftrace 基础设施,最终却发现我们需要的 function_graph 探针由于某种原因无法工作。我们尝试的下一个工具是 perf,但第一次尝试也没有成功。但是,当您最终设法捕获感兴趣的事件时,它们可能会比任何全球计数器更快地引导您找到答案。

最好的问候,尼古拉

相关内容