为什么在没有交换空间的计算机上运行kswapd0?

我有一台云服务器,内存大约为14G,没有交换空间。然而,当我运行top命令时,偶尔会看到kswapd0占用一些CPU。如果没有交换空间需要管理,为什么kswapd0会运行呢?
6个回答

交换空间只用于没有被任何其他文件支持的数据。即使您没有交换设备,也会将从磁盘上的其他文件映射而来的数据(如可执行程序)交换到它们各自的文件中。


17例如,考虑一种情况,你的系统没有进行交换操作,并且内存几乎用尽。内核会从 Firefox 等应用程序中获取内存(因为 Firefox 正在运行从磁盘加载的可执行代码 - 如果需要,该代码可以再次从磁盘加载)。如果 Firefox 在 N 秒后需要再次访问那块内存,CPU 会生成“硬错误”,强制 Linux 释放一些内存(例如从另一个进程中获取一些内存),从磁盘加载丢失的数据,然后允许 Firefox 继续正常运行。这与正常的交换操作非常相似,kswapd0 负责执行此操作。 - Mikko Rantalainen

众所周知,当Linux内存不足时,它可能会陷入交换循环,而不是按照应有的方式杀死进程以释放内存。虽然有一个OOM(内存不足)杀手可以做到这一点,但前提是交换空间和RAM都已满。
然而,这实际上不应该成为问题。如果有一堆有问题的进程,例如Firefox和Chrome,每个进程都有使用和占用内存的标签,那么这些进程将导致交换读回。Linux随后进入一个循环,在内存和硬盘之间来回移动相同的内存。这反过来会导致“优先级倒置”,即来回交换几个进程会使系统无响应。
如果禁用交换空间,问题会变得更糟,因为kswapd0现在没有其他选择,只能交换映射内存,如可执行文件。如果交换出可执行文件,它们很可能会很快被交换回来。
我尝试在NetBSD上触发这种行为进行测试,结果是有问题的进程变得非常慢,而操作系统本身则非常响应。这意味着确实存在交换问题,但没有优先级倒置。然而,NetBSD没有AMDGPU驱动程序,所以我暂时还是选择使用Linux。也许NetBSD不会对可执行文件进行内存映射,这就解释了为什么它不会陷入交换循环,但我对其实现了解不够,无法说出具体原因导致其不会变得无响应。
Facebook也遇到过这个问题,并创建了OOMD(Out Of Memory Daemon),这是一个检测kswapd0活动并开始终止进程的守护程序。据Facebook称,这几乎完全消除了Linux服务器变得无响应的问题。然而,我还没有测试过它,也不知道它在其他服务器或台式机/笔记本电脑上的工作效果如何。值得注意的是,OOMD有一些逻辑来决定首先终止哪些进程,以保留系统进程和负责重新启动被终止进程的服务器系统的部分。
然而,这并不是解决问题的正确方式。OOMD是一个丑陋的补丁。真正的解决方案是修复交换循环引起的优先级反转问题,并使内核的OOM Killer在杀死进程以释放内存时更加积极。修复应该放在内核中,因为只有在那里我们才能确保问题及时被检测到并且进程被正确终止。
将swappiness=0设置为解决方案也不可行,因为当系统没有空闲RAM时,它会开始进行交换操作,无论如何都无法保证系统不会开始交换。
而且修复有问题的应用程序并不能解决问题。尤其是当用户想要利用这个漏洞故意使操作系统无响应时。保持响应性是内核的责任。如果Firefox自己变得无响应,那么解决方法就是修复应用程序。然而,它不仅使自己无响应,还导致整个操作系统变得非常缓慢和无响应。以至于登录SSH可能需要半个小时。SSH与此无关,如果无法运行,那是内核的错误,而不是系统的其他部分。而且这不是一个错误,而是两个错误。一个错误是优先级倒置,允许失控的交换循环干扰其他进程,而不仅仅是有问题的进程,这本身就是不好的。另一个错误是它无法检测到自己处于交换循环中,这会对支持交换的硬盘/固态硬盘或其他存储设备造成极大的磨损。当交换可执行文件时,这个问题就不那么严重了,因为它们是只读内存映射,不会写回到磁盘,但kswapd0仍然被锁定,同时从内存中删除正在读取的内容。
哦,还有第三个bug。没有办法保护磁盘缓存不被内存占用过多的应用程序吞噬。这就是kswapd0导致系统无响应的原因之一。最常用的内存映射数据通常存储在磁盘缓存中,但当Firefox吞噬了该缓存时,显然会导致磁盘读取发生。
并不一定是Firefox引起了您的问题,而是默认浏览器,并非Chrome。这两者都被广泛认为会触发此问题,因为它们将可用内存视为浪费,包括缓存和交换内存,在Linux中计为“可用内存”。所以为了不让“可用内存”被浪费,它们将其用于缓存和其他操作。显然,将交换空间用作磁盘缓存是一个非常糟糕的主意,但是Firefox和Chrome的开发人员对此的回应是“空闲内存是浪费的内存”。
所以我们在这里有三个内核漏洞,内核团队似乎不认为它们是漏洞。还有一个在Firefox、Chrome和所有衍生产品中的bug,他们也不认为是bug。我试图在我的Fedora笔记本上构建Firefox,以便研究并可能修复这个问题。你猜怎么着。使用GCC在4核CPU和4GB内存的情况下构建Firefox会触发SWAP LOOP和PRIORITY INVERSION。所以其中一个必须重写的应用程序就是GCC。在NetBSD上发生的情况只是4个运行实例的GCC比运行一个实例要慢,但不会冻结系统。
是的,这有点发牢骚,但我希望这能澄清Linux内存子系统及其引起的应用程序的当前问题。

有没有办法确保SSH保持响应? - jiggunjer
不。有可能通过chroups来限制内存使用。还有早期的OOM killer可以在发生内存过度使用之前捕获许多情况。但我所知道的确保这一点的唯一方法是运行NetBSD。 - user1657170
@jiggunjer,你可能可以增加SSH超时时间。例如,如果系统正在频繁访问磁盘,SSH登录可能需要几分钟才能获得CPU时间。因此,在某些情况下,你可以增加SSH超时时间,这样可能会在一些情况下起作用,具体取决于延迟的长短。 - Owl
1@Owl 谢谢,结果证明我的kswapd0是加密挖矿程序。 - jiggunjer

它仍然有一个检查是否存在交换的过程。要减少它,您需要设置您的swappiness -
作为root用户编辑“/etc/sysctl.conf”,然后更改(或添加)
vm.swappiness = 0

4好的,但为什么它使用了我的CPU的1%? - benathon
3如果kswapd0占用了任何CPU资源,并且您没有交换空间,那么系统的RAM几乎用完了,并且正在尝试通过(实际上)从可执行文件中交换页面来处理这种情况。正确的解决方法是减少工作负载,添加交换空间或者(最好的选择)安装更多的RAM。添加交换空间将提高性能,因为内核将有更多关于要交换到磁盘的内容的选项。如果没有交换空间,内核实际上被迫交换应用程序代码。 - Mikko Rantalainen
1如果您启用了交换空间并且kswapd0正在使用一些CPU,而您不希望它这样做,请降低swappiness设置。然而,除非您的交换空间由受写入影响的SSD支持(例如,存在糟糕的磨损平衡算法),降低swappiness会降低系统的整体性能。这个想法是保持交换空间中RAM的一个副本,以防需要更多的RAM - 在这种情况下,RAM中的副本将立即被丢弃,而不是在RAM可以使用之前开始进行交换。这种乐观的交换只在系统足够空闲时进行,因此不应该减慢您的系统。 - Mikko Rantalainen

如果您没有交换空间并且kswapd0正在运行,那么您的系统实际上在那一刻几乎使用了所有的RAM。现在是时候获取更好的工具来监控内存使用情况(或系统中的可用/空闲内存)了。
例如,考虑这样一种情况:您没有交换空间,系统几乎用完了RAM。内核将从Firefox等应用程序中获取内存(因为Firefox正在运行从磁盘加载的可执行代码 - 如果需要,该代码稍后可以再次从磁盘加载)。如果Firefox在N秒后需要再次访问该RAM,CPU会生成“硬错误”,强制Linux内核释放一些RAM(例如从另一个进程中获取一些RAM),从磁盘加载丢失的数据,然后允许Firefox继续正常运行。这与正常的交换非常相似,而kswapd0就是这样做的。
真正的解决方法是减少内存使用量(运行具有较少内存泄漏的进程,运行较少的进程,跳过某些进程的运行,限制某些服务器软件的子进程/工作进程数量)或者增加RAM。如果RAM需求是由于内存泄漏引起的,您可以选择使用交换空间。在足够的时间内,Linux应该能够很聪明地将泄漏的部分放入交换空间。拥有交换空间总比没有好,但这并不能真正替代具有足够RAM的情况。

这里有很好的信息,以及你的评论中也有。但是,在所有可用内存(RAM + 交换空间)都被填满的极限情况下,启用交换空间并不是一个解决方案。在内存泄漏的情况下,这是一个特别糟糕的解决方案,因为所有内存最终都会变满。当交换空间和RAM都满时,结果与RAM满而交换空间禁用时相同。 - Codebling
没有拥有无限RAM的系统,这正是你需要确保系统稳定性以防内存泄漏的情况。即使是最小的泄漏也会最终导致系统崩溃。 - user1657170
只是为了明确一点:添加交换空间来处理内存泄漏只是一个权宜之计,而不是修复方法。添加交换空间来保存泄漏的内存比获取RAM来保存泄漏的内存更便宜,只要内存实际上是泄漏的,就不会从交换空间中读取回来。然而,内核无法确定单个页面是泄漏还是很少使用,因此您必须始终存储所有页面,并准备好如果活动页面被错误地交换而不是纯粹的泄漏页面,则会出现减速的情况。通常更好的选择是使用“内存控制组”(memory cgroups),并在泄漏严重时杀死和重新启动泄漏的进程。 - Mikko Rantalainen

恶意软件作为访客运行。
如果您曾经启用Ubuntu的访客帐户,然后启用了SSH,可能会使用您的访客帐户运行恶意软件。
sudo find /home -f kswapd0

你可能会在/home/guest/.configrc/下找到它。
许多人在今天的机器上发现这个问题,这些机器不需要交换,并且他们的可用内存是正常的,只是发现已经安装了挖矿软件并在guest账户下运行,甚至在启动时自动运行。
其中一个迹象是单个CPU核心被限制在100%,而磁盘活动是正常的。在我的情况下,电脑异常炎热,并有异常数量的出站网络数据。
加入任何一个存在受损机器的网络(会议、咖啡馆、城市),或者如果你使用像ngrok这样的服务,同时在你的系统上开放SSH,都会使你的计算机暴露在这种简单的guest漏洞之下。
关于这个问题的专门条目在这里:CPU 100% with kswapd0 process, although no swap is needed

我曾经遇到过一个问题,我的笔记本电脑占用了大量的RAM,没有交换空间,导致我的电脑完全挂起。自动杀死有问题的进程似乎不起作用,所以现在我确保安装了交换空间,以稳定我的机器。这似乎起到了作用。 就像20年前的Linux一样,它只是杀掉了不适合的东西,然后就完成了,现在每次占用太多RAM时,我都必须强制重启我的机器,这真的不是我所期望的。


当Linux的RAM用尽且没有交换空间时,内核将开始终止进程。如果该进程恰好对系统的运行至关重要...那么你的系统就会崩溃。 - Brian Turek
@BrianTurek,这不是我的观察。kswapd0刚刚失控了,没有任何进程被杀死,我系统反复挂起,大量磁盘IO开始(看到硬盘访问灯在闪烁)。如果内核自动杀死关键进程而不是用户空间进程,那也是一个bug。我在这里发表我的回应,给那些遇到同样问题但不知道发生了什么的人一个指引 - 希望有人能读到这个,现在的情况很糟糕,得分已经是-2了。 - Frischling