为什么即使我有足够的可用内存,还要使用交换空间?

我以为交换分区的整个本质是在RAM满了的时候充当一个临时存储安全网,但是我的交换分区经常被使用,即使有时候我有多达3GB的空闲RAM。这正常吗?

5请分享以下命令/文件的内容或输出,以便更好地帮助我们解决您的问题:(此答案中的说明)free -mtop -b 1 - ish
6个回答

你可以尝试更改你的"swappiness"值:
Ubuntu的Swap FAQ中获取的信息:
什么是swappiness,如何更改它?
swappiness参数控制内核将进程从物理内存移出并移到交换磁盘的倾向。由于磁盘比RAM慢得多,如果进程过于积极地被移出内存,这可能导致系统和应用程序的响应时间变慢。
swappiness的值可以在0到100之间。
swappiness=0告诉内核尽可能避免将进程从物理内存中移出。对于3.5版本及更高版本的内核,它会禁用swappiness。
swappiness=100告诉内核积极地将进程从物理内存中移出,并将它们移到交换缓存中。
Ubuntu的默认设置是swappiness=60。减小swappiness的默认值可能会提高典型的Ubuntu桌面安装的整体性能。推荐使用swappiness=10的值,但也可以自行尝试。注意:Ubuntu服务器安装与桌面系统有不同的性能要求,默认值60可能更适合。
检查swappiness值:
cat /proc/sys/vm/swappiness
更改swappiness值:可以使用以下命令进行临时更改(重启后失效),将swappiness值设置为10:
sudo sysctl vm.swappiness=10
要进行永久更改,请使用您喜欢的编辑器编辑配置文件:
gksudo gedit /etc/sysctl.conf
搜索vm.swappiness并根据需要更改其值。如果vm.swappiness不存在,请在文件末尾添加如下内容:
vm.swappiness=10
保存文件并重新启动。
编辑文件后,运行sudo sysctl --load=/etc/sysctl.conf来应用更改。
此外,您还可以查看:https://askubuntu.com/a/103916/54187

1纯属猜测:这实际上可能对性能有益处——很久没有访问的页面可以被复制到交换空间,这样操作系统在需要内存时可以快速清除它们,但页面内容仍然保留在内存中。 - Simon Richter
11@SimonRichter 是的,那就是我的想法。但对于现代系统来说,Swappiness为60可能太过激进了,因为这意味着当您还有几十GB的空闲内存时,就开始进行交换操作。 - Brendan Long

首先,你的“free”定义有几个不同的方面。在Linux(或任何现代操作系统)中,实际上并不像听起来那么简单。
Linux如何使用RAM(非常简化的解释)
每个应用程序都可以使用一些内存。Linux将除了最后几个Mb之外的所有未使用的内存都作为“缓存”使用。这包括页面缓存、inode缓存等。这是一件好事——它可以大大加快速度。无论是写入磁盘还是从磁盘读取,都可以通过缓存来提高速度。
理想情况下,你的内存足够运行所有应用程序,并且还剩下几百Mb用于缓存。在这种情况下,只要应用程序不增加内存使用量,系统不会为缓存而奋斗以获取足够的空间,就不需要交换空间。
一旦应用程序需要更多的RAM,它就会占用一部分之前被缓存使用的空间,从而缩小缓存。释放缓存是非常廉价和容易的,因此可以实时进行 - 缓存中的所有内容要么只是磁盘上已经存在的某个东西的副本,所以可以立即释放,要么是我们在接下来的几秒钟内必须刷新到磁盘上的东西。
这不是Linux特有的情况 - 所有现代操作系统都是这样工作的。不同的操作系统可能只是以不同的方式报告可用RAM:有些将缓存包括在他们认为的“可用”内,而有些则不包括。
当谈论可用RAM时,将缓存纳入其中更有意义,因为它实际上是可用的 - 只要应用程序请求,它就可以使用。在Linux上,`free`命令以两种方式报告 - 第一行将缓存包括在已使用的RAM列中,第二行将缓存(和缓冲区)包括在空闲列中。 Linux如何使用交换空间(更简化) 一旦使用的内存足够多,以至于没有足够的内存供流畅运行的缓存使用,Linux可能会决定将一些未使用的应用程序内存从RAM重新分配到交换空间。
它并不是根据一个明确的截止点来执行这个操作。不像你达到一定的内存分配百分比,Linux就开始进行交换。它有一个相对模糊的算法。它考虑了很多因素,最好用“内存分配的压力有多大”来描述。如果有很大的“压力”来分配新的内存,那么它会增加一些被交换的机会以腾出更多空间。如果“压力”较小,那么它会减少这些机会。
您的系统有一个“swappiness”设置,可以帮助您调整如何计算这种“压力”。通常不建议修改这个设置,我也不建议您修改它。交换总体上是一件非常好的事情 - 尽管在一些特殊情况下可能会影响性能,但从整体系统性能来看,它对各种任务都是有益的。如果您降低了swappiness,即使在实际上可能非常有用的情况下,缓存内存的数量也会比原本更少一些。是否为您遇到的交换问题做出足够好的权衡取决于您自己。您只需要知道自己在做什么,就可以了。
在桌面系统中,有一种众所周知的情况,即交换对于用户感知的性能真正造成了损害。这种情况发生在应用程序在长时间闲置并且后台进程进行大量IO操作(例如过夜备份)后,再次响应用户输入的速度。这是一种非常明显的迟缓,但不足以完全关闭交换,并且在任何操作系统中都很难防止。关闭交换可能会导致备份/病毒扫描后的初始迟缓不会发生,但系统可能整天运行得稍微慢一些。这种情况不仅限于Linux。
在选择要交换到磁盘的内容时,系统尝试选择实际上未被使用(读取或写入)的内存。它有一个相当简单的算法来计算这一点,大部分时间都选择得很好。
如果您的系统拥有大量的RAM(目前为止,对于典型的Linux发行版来说,8GB已经是非常大的数量),那么您几乎不会遇到需要交换的情况。您甚至可以尝试关闭交换。我从不建议这样做,只是因为您永远不知道更多的RAM可能会使您免受某些应用程序崩溃的困扰。但如果您知道您不需要它,您是可以这样做的。
但是交换如何加快我的系统?交换不会减慢速度吗?
将数据从RAM转移到交换空间是一个缓慢的操作,但只有在内核相当确定整体效益超过这一点时才会执行。例如,如果您的应用程序内存增加到几乎没有缓存剩余,并且由于此原因导致I/O非常低效,即使在交换数据以释放内存的初始开销之后,实际上仍然可以从系统中获得更高的速度。
它也是一种最后的手段,当您的应用程序实际上请求比您实际拥有的内存更多时。在这种情况下,交换是必要的,以防止内存不足的情况,否则往往会导致应用程序崩溃或被强制终止。
交换只与系统性能不佳的时候相关,因为它发生在您的可用RAM不足的时候,即使没有交换,这也会减慢系统速度(或使其不稳定)。所以简单来说,交换发生是因为您的系统变得拖累,而不是反过来。
一旦数据进入交换空间,它何时再次出来?
将数据从交换空间中转移出来(至少对于传统硬盘而言)与将其放入其中一样耗时。因此,可以理解为,如果数据实际上没有被使用(即未读取或写入),您的内核将不愿意从交换空间中删除数据。如果您的数据在交换空间中且未被使用,那么它仍然保留在交换空间中实际上是件好事,因为这样可以为其他正在被使用的内容留下更多的内存,从而可能加快系统速度。

11+1 给详细解释。我也喜欢在我的电脑上保留2GiB的交换空间。如果出现问题,比如内存泄漏等,你可以看到交换空间的使用量增加,并在内存耗尽之前寻找问题所在。它既是一个安全网,也是一个性能工具。 - Joe
2在我的迷你笔记本上,只有2GB的内存,我保留了4GB的交换空间。这是因为我将迷你笔记本用于比它原本设计用途更多的任务,并且我的程序经常需要超过2GB的内存。由于Linux在内存不足的情况下表现非常糟糕,所以我更喜欢有一个较大的安全垫。而且我有足够的磁盘空间。 - Scott Severance
如果你的程序经常需要超过2GB的内存,我建议你增加更多的RAM(它非常便宜!),因为耗尽内存会影响性能。为了其他读者的利益:确保你不仅仅关注缓存内存,它本来就会占用可用的内存 - 参考其他关于free -m的信息。 - thomasrutter
2@neon_overload: 我应该提醒一下,根据惠普的说法,我的上网本的最大内存只有1GB。目前我已经装了2GB的内存,而网络信息表明2GB是实际可扩展的最大容量。因此,需要采取这种解决办法来解决问题。 - Scott Severance
2@thomasrutter:对于大型服务器,你的回答会有什么变化呢?我的其中一台服务器有1TB(是的,整整1TB)的内存,但仍在使用交换空间;你会建议设置什么样的swappiness值和交换分区大小呢? - chrisinmtown
1我建议首先对使用了1TB并需要更多空间的服务器进行更多分析,并解决这个问题。交换是潜在问题(低内存)的症状,而不是原因,在这种情况下调整swappiness就像在泰坦尼克号上重新排列甲板椅一样。有swap是明智的,以防有时需要它,但如果你通常看到服务器上交换了许多GB,则说明有些地方出了问题。对于负载相对均匀的服务器,您应该目标是几乎不使用任何交换。 - thomasrutter
这是我在任何地方找到的关于Linux内存使用的最清晰的解释。谢谢! - Dan Barron
我觉得最好彻底禁用交换空间。目前我的情况是,我有64GiB的内存,主要供Postgres使用,而且我已经将Postgres的共享缓冲区大小设置为30GiB。有10个Postgres进程在运行,每个进程的SHR都是30GiB。我的系统频繁地进行交换操作,导致严重的延迟。有45GiB的“缓存内存”(也就是空闲内存)闲置着,却没有被利用!我认为系统被Postgres进程的SHR内存所欺骗,以为我内存不足。 - sudo
1如果您的系统交换严重,禁用交换可能会导致更多问题。您可能错误地配置了Postgres,或者某些程序可能使用的内存比您意识到的要多得多。交换系统不会被“愚弄”-它清楚地知道哪些页面被分配给了什么目的,因为这都在内核中。首先,确定是否真的是在交换,还是磁盘活动没有进行交换。然后,确定为什么您的系统无法分配RAM。我对Postgres如何使用内存的了解不够,无法提供更多帮助。 - thomasrutter

设置 swappiness 值并不在所有情况下都有效。如果对您有效,很好。如果没有效果,我编写了一个脚本,定期通过关闭然后重新启动来清除交换空间。

如果你不小心切换交换空间,会有一些风险。如果你没有足够的空闲内存来容纳所有的数据和交换空间中的内容,尝试禁用交换空间将导致系统无响应。我的脚本首先检查是否有足够的空闲内存(这需要一些操作,因为实际上的空闲内存量与 free 报告的不同),只有在有足够内存时才切换交换空间。但是,如果你的内存有点不足,请在脚本运行时不要启动另一个重要的进程。以下是脚本:

#!/bin/bash

# Make sure that all text is parsed in the same language
export LC_MESSAGES=en_US.UTF-8
export LC_COLLATE=en_US.UTF-8
export LANG=en_US.utf8
export LANGUAGE=en_US:en
export LC_CTYPE=en_US.UTF-8

# Calculate how much memory and swap is free
free_data="$(free)"
mem_data="$(echo "$free_data" | grep 'Mem:')"
free_mem="$(echo "$mem_data" | awk '{print $4}')"
buffers="$(echo "$mem_data" | awk '{print $6}')"
cache="$(echo "$mem_data" | awk '{print $7}')"
total_free=$((free_mem + buffers + cache))
used_swap="$(echo "$free_data" | grep 'Swap:' | awk '{print $3}')"

echo -e "Free memory:\t$total_free kB ($((total_free / 1024)) MB)\nUsed swap:\t$used_swap kB ($((used_swap / 1024)) MB)"

# Do the work
if [[ $used_swap -eq 0 ]]; then
    echo "Congratulations! No swap is in use."
elif [[ $used_swap -lt $total_free ]]; then
    echo "Freeing swap..."
    swapoff -a
    swapon -a
else
    echo "Not enough free memory. Exiting."
    exit 1
fi

你必须以root身份运行这个脚本(例如,使用sudo)。这个脚本不会导致你的系统无响应;如果你的RAM不足,它将拒绝切换交换空间。我已经使用这个脚本近五年了,没有遇到任何问题。

1+1 表示赞同脚本。你可能想要现代化一下,将输出中的 MB 改成 MiB。我写了一个类似的脚本,但没有你包含的(好)安全测试。在我旧的笔记本上,交换空间经常被使用,运行时间会比较长 - 大约一两分钟,但并不会对任何东西造成损害。偶尔会因为没有足够的可用内存而运行失败,但这不会导致任何其他问题。当发生这种情况时,我不得不重启来清理一切。这与 Transmission 中的一个内存泄漏问题有关(我相信这个问题已经修复了),以及只有 2GiB 的内存有关。 - Joe
6如果某个数据被移动到交换空间并且仍然留在交换空间,这通常是一件好事-这意味着该数据实际上并没有被使用,并且已经为其他东西释放了一些RAM,从而潜在地提高了速度。是什么让你认为这些数据不应该在交换空间中,并且应该占用更宝贵的RAM呢?通常情况下,内核非常擅长知道哪些数据未使用,并且可以安全地保留在交换空间中以释放RAM。 - thomasrutter
1@neon:记住,我的机器分别只有2GB和3GB的RAM,这在如今来说相当少了。性能就是证明。例如,弹出菜单或切换程序可能会因为交换而变慢,Compos视觉效果也是如此。通过切换交换空间可以解决这种缓慢的问题,从而证明至少在某些情况下,内核的优化算法并不是最优的。我无法反驳反复的经验。 - Scott Severance
哎呀!这刚刚降到了0%的交换空间……我没有太多时间来仔细研究这个完整的问题及其答案,但我把它收藏起来,等我有空闲时间时再读一下。 - AzkerM
为什么不直接将swappiness设置为一个较低的值呢?这似乎与你的脚本做的事情相同,但更加可控。 - jhfrontz
@jhfrontz:实际上,swappiness只影响内核如何积极地将东西交换出去。几年前我编写这个脚本时,将swappiness设置为较低的值对于内存有限的机器没有明显的影响(尤其是快速的影响)。 - Scott Severance
我在想,将swappiness设置为0(在启动时)意味着“除非你真的、真的、真的必须交换”,因此,唯一被交换的将是系统继续运行所必需的内容。 - jhfrontz
2当然,但这并没有解决一旦内存被释放,而交换空间中仍然有东西的问题,尽管现在有足够的空闲内存。内核不会在需要之前将其从交换空间中取出,这可能会导致系统响应性方面的重大问题。(考虑一下当系统菜单全部被交换出去时:只有在点击菜单按钮后才会被交换回来,这意味着你突然需要等待一段时间才能弹出菜单。)这就是为什么在适当的时候手动将其从交换空间中取出可以提高系统响应性的原因。 - Scott Severance
好观点;我没有考虑到防止OOM后的交换恢复场景。 - jhfrontz
我只是想指出,对于具有可写入的最大字节数(也称为耐久性)的SSD来说,这是一个救命稻草。除非我内存用尽,否则我不希望发生交换,一旦我有足够的内存,我希望将所有内容都放回内存中,以防止损坏我的SSD。这也适用于服务器,如果在剩余的一天里,我的用户都能执行非常快速的操作,那么我对清除交换区的2分钟毫不在意。 - Tmanok
所有这些东西都是可调的(查看/proc/sys/vm/)。 - france1
语言不应该是:export LANGUAGE=en_US.UTF-8吗? - alper

我编辑了Scott Severance的脚本,以匹配已经包含总可用内存字段的较新版本的free。
#!/bin/bash

free_mem="$(free | grep 'Mem:' | awk '{print $7}')"
used_swap="$(free | grep 'Swap:' | awk '{print $3}')"

echo -e "Free memory:\t$free_mem kB ($((free_mem / 1024)) MiB)\nUsed swap:\t$used_swap kB ($((used_swap / 1024)) MiB)"
if [[ $used_swap -eq 0 ]]; then
    echo "Congratulations! No swap is in use."
elif [[ $used_swap -lt $free_mem ]]; then
    echo "Freeing swap..."
    sudo swapoff -a
    sudo swapon -a
else
    echo "Not enough free memory. Exiting."
    exit 1
fi

1使用这类脚本需要注意的一点是,它们能有效地清除交换空间,但如果不清理缓冲区和缓存,你将立即开始进行交换。例如,在运行此脚本不到一秒钟后,我开始积累更多的交换空间。这在htop中非常容易看到。关于缓存、缓存压力、缓冲区和缓存对工作内存的"让路"速度等问题存在很多争议。但对我来说,我只需使用"sync"命令并告诉内核清除缓存即可消除它们。 - Tmanok

通常情况下,现今的系统很少使用交换空间。根据我的经验,长时间运行且没有密集操作的进程会被Linux转移到交换空间中。
这会导致一些受影响的程序运行缓慢。
如果你有大量可用的内存,你可以通过运行以下命令关闭交换空间:
swapoff -av(需要sudo权限)。
如果你不想关闭交换空间,你可以使用对称的命令打开它:
swapon -av(同样需要sudo权限)。

18完全关闭交换空间是过度杀伤力的,因为swapiness=0可以达到同样的效果,但更安全(如果你的内存中确实有太多东西,它会将一些内容放入交换空间)。 - Brendan Long
10年后的评论:如果你的系统有256GB的内存,但仍然出现内存不足的情况,那么几个GB的交换空间也无济于事... - Stefan Paul Noack

一旦交换已经被程序使用,它往往会在程序的生命周期内保持映射。许多程序有很少使用的代码(和数据)。一旦内存被交换出去,它就不太可能再次被交换回来。
强制将这些页面加载到内存中的一种方法是关闭交换设备。如果你有两个交换设备,你可以关闭一个,然后重新打开它,然后关闭第二个。如果真的需要交换空间,它将在设备之间移动。你也可以只关闭交换设备(或文件),但如果你真的需要交换空间,可能会发生严重的事情。
除了内存中的正常内容外,tempfs也使用交换空间,并且会像其他内存一样进行交换。如果运行需要大量临时磁盘的任务,它可能会导致页面被交换出去。一旦创建的临时文件在几分钟后可能不再使用,并且是移动到交换设备的好选择。
在紧急情况下,您可以使用文件作为交换设备。这在您需要临时额外的交换空间时非常有用。

这是一个准确的描述,解释了为什么在导致数据被交换出去的情况之后,数据仍然保留在交换空间中。 - thomasrutter