什么是Linux上的Swappness?(以及如何改变它)

Linux交换值与开始交换之前使用了多少RAM无关。这是一个被广泛报道和普遍认为的错误。我们解释它到底是什么。

打破关于互换的迷思

交换是一种将随机存取存储器(RAM)中的数据写入硬盘上的特殊位置(交换分区或交换文件)以释放RAM的技术。

Linux有一个称为交换值的设置。关于这个设置控制的是什么,人们有很多困惑。对交换性最常见的错误描述是,它为RAM使用设置了一个阈值,当使用的RAM数量达到这个阈值时,交换就开始了。

这是一个经常被重复的误解,现在已经成为公认的智慧。如果(几乎)每个人都告诉你,这就是掉期的工作原理,那么当我们说它不是这样的时候,你为什么要相信我们呢?

很简单。我们会证明这一点的。

您的RAM被拆分为多个区域

Linux不会将您的RAM视为一个大的同构内存池。它认为它被分成许多不同的区域,称为区域。您的计算机上存在哪些区域取决于它是32位还是64位。下面是x86架构计算机上可能的区域的简化描述。

直接内存访问(DMA):这是最低的16MB内存。该区域之所以得名,是因为很久以前,有些计算机只能直接访问该物理内存区域的内存。 直接内存访问32:尽管名为直接内存访问32(DMA32),但它是一个仅在64位Linux中才能找到的区域。这是最低的4 GB内存。在32位计算机上运行的Linux只能对此数量的RAM执行DMA操作(除非它们使用的是物理地址扩展(PAE)内核),这就是该区域得名的原因。不过,在32位计算机上,它被称为HighMem。 正常:在64位计算机上,正常内存是所有大于4 GB的RAM(大致)。在32位计算机上,它是介于16MB和896MB之间的RAM。 HighMem:这只存在于32位Linux计算机上。它都是896 MB以上的RAM,包括足够大的机器上4 GB以上的RAM。

pageSize值

RAM以页的形式分配,页的大小是固定的。该大小由内核在引导时通过检测计算机的体系结构来确定。通常,Linux计算机上的页面大小为4K字节。

您可以使用getconf命令查看页面大小:

getconf PAGESIZE

区域附加到节点

分区附着到节点。节点与中央处理单元(CPU)相关联。内核将尝试从与CPU关联的节点为在CPU上运行的进程分配内存。

节点绑定到CPU的概念允许在使用非统一内存访问体系结构的专业多CPU计算机中安装混合内存类型。

这些都是非常高端的。一台普通的Linux计算机将只有一个节点,称为节点零。所有区域都将属于该节点。要查看计算机中的节点和区域,请查看/proc/budyinfo文件。我们将使用较少的资源来做到这一点:

less /proc/buddyinfo

这是本文研究的64位计算机的输出:

Node 0, zone DMA 1 1 1 0 2 1 1 0 1 1 3 Node 0, zone DMA32 2 67 58 19 8 3 3 1 1 1 17

只有一个节点,节点零。这台计算机只有2 GB的RAM,所以没有“正常”区域。只有两个分区,DMA和DMA32。

每列表示特定大小的可用页数。例如,对于DMA32区域,从左开始读取:

2:有2个,共2^(0*pageSize)个内存块。 67:有67个2^(1*page_size)内存块。 58:有2^(2*pageSize)个内存块中的58个可用。 以此类推,一直到…。 17:共有2^(512*pageSize)块中的17个。

但实际上,我们查看此信息的唯一原因是要了解节点和区域之间的关系。

文件页面和匿名页面

内存映射使用页表条目集来记录使用了哪些内存页以及使用的目的。

内存映射可以是:

文件备份:文件备份映射包含从文件读取的数据。它可以是任何类型的文件。需要注意的重要一点是,如果系统释放了该内存并需要再次获取该数据,则可以再次从文件中读取该数据。但是,如果内存中的数据已更改,则需要将这些更改写入硬盘上的文件,然后才能释放内存。如果不这样做,更改就会丢失。 匿名:匿名内存是没有文件或设备支持的内存映射。这些页面可能包含程序动态请求的内存,以保存数据,或者用于堆栈和堆之类的东西。因为这种类型的数据背后没有文件,所以必须留出一个特殊的地方来存储匿名数据。该位置是交换分区或交换文件。匿名数据在释放匿名页之前写入交换。 设备备份:设备通过块设备文件寻址,可以将其视为文件。可以从它们中读取数据并向其写入数据。设备备份的存储器映射中存储有来自设备的数据。 共享:多个页表条目可以映射到RAM的同一页。通过任何映射访问内存位置都将显示相同的数据。通过更改这些共同监视的内存位置中的数据,不同的进程可以非常高效地相互通信。共享可写映射是实现高性能进程间通信的常用方法。 写入时复制:写入时复制是一种懒惰的分配技术。如果请求已在内存中的资源的副本,则通过返回到原始资源的映射来满足该请求。如果“共享”该资源的某个进程试图写入该资源,则必须在内存中真正复制该资源,以允许对新副本进行更改。因此,内存分配仅在第一个写命令时进行。

对于交换,我们只需要关注列表中的前两个:文件页和匿名页。

可交换性

以下是GitHub上的Linux文档中对交换的描述:

“此控制用于定义内核交换内存页的积极程度(SIC)。较高的值将增加积极程度,较低的值将减少交换量。0值指示内核在空闲和文件备份的页数小于区域中的高水位线之前不要启动交换。

默认值为60。“

这听起来像是掉期使掉期的强度上升或下降。有趣的是,它声明将swappness设置为零并不会关闭交换。它指示内核在满足某些条件之前不要交换。但掉期仍有可能发生。

让我们再深挖一遍。内核源代码文件vmscan.c中的vm_swappity的定义和默认值如下:

/*。 *从0开始..。100.。越高意味着越易交换。 */。 int VM_swappness=60;

交换值的范围可以从0到100。同样,评论听起来肯定像是交换值与交换量有关系,数字越高,交换越多。

进一步在源代码文件中,我们可以看到一个名为“swappness”的新变量被赋予了一个值,该值由函数mem_cgroup_swappness()返回。进一步跟踪源代码会发现,该函数返回的值是vm_swappness。因此,现在,变量sswappness被设置为等于VM_swappness设置的任何值。

int swappness=mem_cgroup_swappness(Memcg);

再往下看同一源代码文件,我们可以看到以下内容:

/*。 *交换度为100时,匿名和文件具有相同的优先级。 *此扫描优先级实质上与IO成本相反。 */。 ANON_PRIO=交换; FILE_PRIO=200-ANON_PRIO;

这很有趣。两个截然不同的值派生自交换性。ANON_PRIO和FILE_PRIO变量保存这些值。一个增加了,另一个减少了,反之亦然。

Linux交换值实际上设置两个值之间的比率。

黄金比例

如果释放内存,文件页保存的数据很容易检索。Linux只需再次读取该文件即可。正如我们已经看到的,如果RAM中的文件数据已更改,则必须将这些更改写入文件,然后才能释放文件页。但是,无论哪种方式,RAM中的文件页都可以通过从文件中读取数据来重新填充。那么,为什么要费心将这些页添加到交换分区或交换文件中呢?如果您再次需要该数据,您不妨从原始文件中读回它,而不是交换空间中的冗余副本。因此,文件页不会存储在交换空间中。它们被“存储”回原始文件中。

对于匿名页,没有与内存中的值相关联的底层文件。这些页面中的值是动态得出的。您不能简单地从文件中读回它们。恢复匿名页面内存值的唯一方法是在释放内存之前将数据存储在某个位置。这就是掉期所持有的。您需要再次引用的匿名页面。

但请注意,对于文件页和匿名页,释放内存可能需要硬盘写入。如果文件页数据或匿名页数据自上次写入文件或交换后已更改,则需要文件系统写入。要检索数据,需要读取文件系统。这两种类型的页面回收都很昂贵。试图通过最大限度地减少匿名页面交换来减少硬盘输入和输出,只会增加处理写入文件和从文件读取文件页面所需的硬盘输入和输出量。

正如您从最后的代码片段中看到的,有两个变量。一个名为FILE_PRIO,代表“文件优先级”,另一个名为ANON_PRIO,代表“匿名优先级”。

ANON_PRIO变量设置为Linux交换值。 FILE_PRIO值设置为200减去ANON_PRIO值。

这些变量保存协同工作的值。如果它们都设置为100,则它们相等。对于任何其他值,ANON_PRIO将从100减少到0,FILE_PRIO将从100增加到200。这两个值提供给一个复杂的算法,该算法确定Linux内核运行时优先回收(释放)文件页面还是匿名页面。

您可以认为FILE_PRIO是系统释放文件页面的意愿,ANON_PRIO是系统释放匿名页面的意愿。这些值不做的是为何时使用交换设置任何类型的触发器或阈值。那是在别处决定的。

但是,当需要释放内存时,回收和交换算法会考虑这两个变量以及它们之间的比率,以确定优先考虑释放哪些页面类型。并且这规定了相关联的硬盘驱动器活动是为文件页处理文件还是为匿名页交换空间。

掉期交易实际上是在什么时候切入的?

我们已经确定了Linux交换度值设置了将被扫描以寻找潜在回收的内存页类型的首选项。这很好,但一定要有一些东西来决定掉期交易何时开始。

每个存储区具有高水位线和低水位线。这些是系统派生的值。它们是每个区域中RAM的百分比。正是这些值用作交换触发阈值。

要检查您的最高水位线和最低水位线,请使用以下命令查看/proc/zoneinfo文件内部:

less /proc/zoneinfo

每个区域都将有一组以页为单位测量的内存值。以下是测试计算机上DMA32区域的值。低水位线为13966页,高水位线为16759页:

在正常运行条件下,当某个区域中的空闲内存降至该区域的低水位线以下时,交换算法会开始扫描内存页,以查找可以回收的内存,同时会考虑INANON_PRIO和FILE_PRIO的相对值。 如果Linux交换值设置为零,则当文件页面和空闲页面的总和小于高水位线时,将发生交换。

因此您可以看到,您不能使用Linux swappyy值来影响交换的RAM使用行为。事情就是不是那样运作的。

SWAPINITY应该设置为什么?

这取决于硬件、工作负载、硬盘类型,以及您的计算机是台式机还是服务器。显然,这不会是一个适用于所有类型的设置。

而且你必须记住,交换不仅仅是在内存空间耗尽时用来释放RAM的一种机制,交换是一个运行良好的系统的重要组成部分,没有它,Linux就很难实现正常的内存管理。

更改Linux交换值会立即生效;您不需要重新启动。所以你可以做一些小的调整并监控效果。理想情况下,您应该在计算机上使用不同类型的活动在一段时间内执行此操作,以尽可能找到最接近理想设置的设置。

以下是需要考虑的几点:

试图通过将Linux交换值设置为零来“禁用交换”,只需将与交换相关的硬盘活动转移到与文件相关的硬盘活动即可。 如果您有陈旧的机械硬盘驱动器,您可以尝试降低Linux交换值,以避免匿名页面回收,并减少交换分区丢失。当然,当您关闭一项设置时,另一项设置会增加。减少交换流失量可能会增加文件系统流失率。但是你的计算机可能会更喜欢一种方法而不是另一种方法。真的,唯一确定的方法就是试着去看看。 对于单一用途的服务器(如数据库服务器),您可以从数据库软件供应商那里获得指导。通常,这些应用程序有自己专门设计的文件缓存和内存管理例程,您最好依赖这些例程。软件提供商可以根据机器规格和工作负载建议Linux交换值。 对于拥有相当新硬件的普通台式机用户而言?让它保持原样。

如何设置Linux交换值

在更改交换值之前,您需要知道它的当前值是什么。如果你想减少一点,问题是比什么少一点?您可以使用以下命令找出答案:

cat /proc/sys/vm/swappiness

要配置交换值,请使用以下sysctl命令:

sudo sysctl vm.swappiness=45

新值立即使用,不需要重新启动。

事实上,如果您重新启动,交换值将返回到其默认值60。当您完成实验并决定要使用的新值时,可以通过将其添加到/etc/sysctl.conf文件来使其在重新引导后保持不变。您可以使用您喜欢的任何编辑器。使用以下命令使用Nano编辑器编辑文件:

sudo nano /etc/sysctl.conf

当Nano打开时,滚动到文件底部并添加此行。我们使用35作为永久交换值。您应该替换要使用的值。

vm.swappiness=35

要保存更改并退出Nano,请按“Ctrl+O”,按“Enter”,然后按“Ctrl+Z”。

内存管理很复杂

内存管理很复杂。这就是为什么对于普通用户来说,把它留给内核通常更好。

很容易认为您使用的内存比实际使用的更多。像top和free这样的公用事业公司可能会给人错误的印象。Linux将把空闲RAM用于自己的各种目的,例如磁盘缓存。这人为地提高了“已用”内存数,减少了“空闲”内存数。实际上,用作磁盘缓存的RAM被标记为“已使用”和“可用”,因为它可以随时快速回收。

对于外行来说,这可能看起来互换不起作用,或者互换的值需要更改。

一如既往,魔鬼在于细节。或者,在本例中为守护进程。内核交换守护进程。

相关文章