我有一台云服务器,内存约为 14G,没有交换空间。但是,运行时偶尔会看到 kswapd0 占用一些 CPU top
。如果没有交换空间可供 kswapd0 管理,它为什么还要运行呢?
答案1
交换空间仅用于存储没有其他文件支持的数据。即使没有交换设备,从磁盘上的其他文件(如可执行程序)映射的数据仍会交换到其各自的文件中。
答案2
众所周知,当 Linux 内存不足时,它会进入交换循环,而不是执行其应执行的操作,即终止进程以释放内存。有一个 OOM(内存不足)终止程序可以执行此操作,但前提是交换和内存已满。
但是这实际上不应该是一个问题。如果存在许多有问题的进程,例如 Firefox 和 Chrome,每个进程都有正在使用和抢占内存的选项卡,那么这些进程将导致交换读回。然后 Linux 进入一个循环,其中相同的内存在内存和硬盘之间来回移动。这反过来又导致优先级倒置来回交换几个进程会导致系统无响应。
如果禁用交换,则会使此问题变得更糟,因为 kswapd0 现在别无选择,只能交换出映射内存(如可执行文件)。如果您交换出可执行文件,则更有可能很快将它们交换回来。
我尝试在 NetBSD 中触发此行为进行测试,结果发现有问题的进程变得异常缓慢,而操作系统本身却非常灵敏。这意味着交换问题确实发生了,但没有优先级反转。但是 NetBSD 没有 AMDGPU 驱动程序,所以我暂时坚持使用 Linux。也许 NetBSD 没有内存映射可执行文件,这就是它不进入交换循环的原因,但我对它的实现了解不够多,无法说出它为什么没有变得无响应。
Facebook 也遇到了这个问题,并创建了 OOMD,即内存不足守护进程。这个守护进程会检测 kswapd0 活动并开始终止进程。据 Facebook 称,这几乎完全消除了 Linux 服务器无响应的问题。但是我还没有测试过它,也不知道它在其他服务器或台式机/笔记本电脑上的效果如何。OOMD 的吸引力在于它有一些逻辑来决定首先终止哪些进程,以保留系统进程和服务器系统中负责重新启动被终止进程的部分。
然而,这并不是解决问题的办法。OOMD 是一种 UGLY HACK。真正的解决方案是修复交换循环导致的优先级反转,并使内核 OOM Killer 更积极地终止进程以释放内存。修复应该在内核中进行,因为只有在那里我们才能确保及时检测到问题并正确终止进程。
设置 swappiness=0 不是解决办法,因为当系统没有可用 RAM 时,无论如何它都会开始交换。没有选项可以保证系统不开始交换。
而且修复有问题的应用程序并不是修复。特别是当用户想利用这个错误故意让操作系统不响应时。响应是内核的责任。如果 Firefox 让自己不响应,那么修复就是针对应用程序。然而,它不仅让自己不响应,还导致整个操作系统变得非常缓慢和不响应。甚至可能需要半个小时才能登录 SSH。SSH 与此无关,如果它无法运行,那就是内核的一个错误,而不是系统任何其他部分的一个错误。这不是一个错误,而是两个错误。一个错误是优先级反转,其中允许偏离轨道的交换周期干扰有问题的进程以外的其他进程,这本身就是不好的。另一个错误是它没有检测到它处于交换循环中,这会导致 HDD/SSD 或支持交换的任何存储严重磨损。当交换可执行文件时,这不是什么大问题,因为它们是只读内存映射,不会写回到磁盘,但 kswapd0 仍然被锁定,读取它同时从内存中删除的内容。
哦,还有第三个错误。当内存需求大的应用程序吞噬所有可用内存时,没有办法保护磁盘缓存不被吞噬。这是 kswapd0 使系统无响应的原因之一。最热门的内存映射数据通常存储在磁盘缓存中,但当 Firefox 吞噬了该缓存时,这显然意味着必须进行磁盘读取。
导致您出现问题的不一定是 Firefox,而是默认浏览器,而不是 Chrome。众所周知,两者都会引发此问题,因为它们将可用内存视为浪费,包括缓存和交换内存,在 Linux 中,它们算作“可用内存”。因此,为了不让“可用内存”被浪费,请将其用于缓存和其他内容。显然,将 SWAP 用于磁盘缓存是一个非常糟糕的想法,但 Firefox 和 Chrome 的同事对此的回应是“可用内存就是浪费的内存”。
因此,我们这里有三个内核错误,内核团队似乎并不认为它们是错误。此外,Firefox、Chrome 和所有衍生产品中还有一个错误,他们也不认为它们是错误。我尝试在我的 Fedora 笔记本电脑上构建 Firefox,以便研究这个问题并可能修补它。猜猜怎么着。在 4 核 CPU 和 4GB 内存上用 GCC 构建 Firefox 会触发带有优先级反转的交换循环。因此,必须重写的应用程序之一是 GCC。在 NetBSD 上,发生的情况是,运行的 4 个 GCC 实例比运行一个实例慢,但不会冻结系统。
是的,这有点夸张,但我希望它能够澄清 Linux 内存子系统以及导致该问题的应用程序的当前问题。
答案3
答案4
如果您没有交换分区并且kswapd0
正在运行,那么您的系统实际上此时正在使用几乎所有的 RAM。是时候获取更好的工具来监控内存使用情况(或系统中的空闲/可用内存)了。
例如,假设您的交换空间为零,并且系统的 RAM 即将耗尽。内核将从 Firefox 等程序中获取内存(它之所以这样做是因为 Firefox 正在运行已从磁盘加载的可执行代码 - 如果需要,可以稍后再次从磁盘加载该代码)。如果 Firefox 随后需要在 N 秒后再次访问该 RAM,则 CPU 会产生“硬故障”,迫使 Linux 内核释放一些 RAM(例如从另一个进程中获取一些 RAM),从磁盘加载丢失的数据,然后允许 Firefox 照常继续运行。这与正常交换非常相似,kswapd0 会执行此操作
真正的解决方法是减少内存使用量(运行内存泄漏较少的进程、运行较少的进程、完全跳过运行某些进程、限制某些服务器软件的子进程/工作进程数量)或获取更多 RAM。如果 RAM 需求是由内存泄漏引起的,您可以选择使用交换。Linux 应该非常聪明,只要有足够的时间就可以将泄漏的部分交换到交换中。有交换总比没有好,但这并不能真正替代拥有足够的 RAM。