什么是Linux上的Swappiness 以及如何更改swappiness?
Linux swappiness值与交换开始之前使用了多少内存无关。这是一个被广泛报道并被广泛认为的错误。我们解释它的真正含义。
关于Swapiness
交换是一种将随机存取存储器(RAM)中的数据写入硬盘上特殊位置(交换分区或者交换文件)以释放RAM的技术。
Linux有一个称为swappiness值的设置。此设置所控制的内容引起很多混乱.swappiness的最常见错误描述是它为RAM使用率设置了阈值,并且当已用RAM的数量达到该阈值时,交换开始。
这是一个经常被误解的错误,以至于现在它已经被人们所接受。如果(几乎)其他所有人都告诉你这正是交换的原理,那么为什么当我们说不行的时候你为什么要相信我们呢?
RAM分为区域
Linux不会将RAM视为同一个大的内存池。它认为它被分为许多不同的区域,称为区域。计算机上存在哪些区域取决于它是32位还是64位。这是x86体系结构计算机上可能区域的简化描述。
直接内存访问(DMA):这是低16 MB的内存。该区域之所以得名,是因为很久以前,有些计算机只能直接对物理内存区域进行内存访问。
直接内存访问32:尽管有直接内存访问32(DMA32)的名称,但它是仅在64位Linux中找到的区域。这是低4 GB的内存。在32位计算机上运行的Linux只能对此数量的RAM进行DMA(除非它们使用的是物理地址扩展(PAE)内核),这就是该区域的名称。尽管在32位计算机上,它称为HighMem。
正常:在64位计算机上,正常内存是大于4GB的所有RAM(大约)。在32位计算机上,它是16 MB到896 MB之间的RAM。
HighMem:仅在32位Linux计算机上存在。它是所有大于896 MB的RAM,包括足够大的计算机上大于4 GB的RAM。
PAGESIZE值
RAM以固定大小的页面分配。该大小由内核在启动时通过检测计算机的体系结构确定。通常,Linux计算机上的页面大小为4 KB。
我们可以使用getconf
命令查看页面大小:
getconf PAGESIZE
区域添加到节点
区域连接到节点。节点与中央处理器(CPU)关联。内核将尝试从与该CPU关联的节点为该CPU上运行的进程分配内存。
节点绑定到CPU的概念允许使用非统一内存访问体系结构在专业的多CPU计算机中安装混合内存类型。
那都是非常高端的。一般的Linux计算机将只有一个节点,称为零节点。所有区域都将属于该节点。要查看计算机中的节点和区域,请查看/ proc / buddyinfo
文件内部。我们将使用less
来做到这一点:
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:总共2 ^(1 * PAGE_SIZE)个内存块中有67个。
58:有2个(2 * PAGESIZE)内存块中有58个可用。
依此类推,一直到
17:总共2 ^(512 * PAGESIZE)个块中有17个。
但是,实际上,我们查看此信息的唯一原因是查看节点与区域之间的关系。
文件页面和匿名页面
内存映射使用页表条目集来记录使用哪些内存页以及使用哪些内存页。
内存映射可以是:
支持文件的文件:支持文件的映射包含已从文件读取的数据。它可以是任何类型的文件。需要注意的重要一点是,如果系统释放了该内存并需要再次获取该数据,则可以再次从文件中读取该数据。但是,如果已更改内存中的数据,则需要先将这些更改写入硬盘驱动器上的文件,然后才能释放内存。如果没有发生,更改将丢失。
匿名:匿名内存是没有文件或者设备支持的内存映射。这些页面可能包含程序为存储数据而动态请求的内存,或者用于堆栈和堆之类的东西。由于这种类型的数据后面没有文件,因此必须在特殊位置保留用于存储匿名数据的位置。那个地方是交换分区或者交换文件。在释放匿名页面之前,将写入匿名数据以进行交换。
支持设备的设备:通过块设备文件对设备进行寻址,可以将它们视为文件。可以从它们读取数据并将其写入。设备支持的内存映射中存储有来自设备的数据。
共享:多个页表条目可以映射到RAM的同一页。通过任何映射访问内存位置将显示相同的数据。通过更改这些共同监视的内存位置中的数据,不同的进程可以以非常有效的方式相互通信。共享的可写映射是实现高性能进程间通信的常用方法。
写时复制:写时复制是一种惰性分配技术。如果请求已经在内存中的资源的副本,则通过返回到原始资源的映射来满足该请求。如果共享资源的进程之一尝试写入该资源,则必须在内存中真正复制该资源以允许对新副本进行更改。因此,内存分配仅发生在第一个写命令上。
为了交换,我们只需要关心列表中的前两个:文件页面和匿名页面。
Swappiness
这是GitHub上Linux文档中对swappiness的描述:
""此控件用于定义内核将如何积极地交换内存页面。较高的值将增加积极性,较低的值将减少交换量。值0指示内核在可用量之前不要启动交换并且文件支持的页面小于区域中的高水位线。
"默认值为60。"
听起来好像交换会增加或者降低交换强度。有趣的是,它指出将swappiness设置为零不会关闭交换。它指示内核在满足某些条件之前不要交换。但是交换仍然可能发生。
让我们深入研究。这是内核源代码文件vmscan.c中vm_swappiness的定义和默认值:
`/ *
*从0 .. 100开始。较高意味着更多交换。
- /
整数vm_swappiness = 60;
swappiness值的范围可以从0到100。同样,注释肯定听起来像swappiness值与发生多少交换有关,较高的数字会导致更多的交换。
在源代码文件中,进一步可以看到一个名为" swappiness"的新变量被分配了一个值,该值由函数" mem_cgroup_swappiness()"返回。通过对源代码的进一步跟踪,可以发现此函数返回的值为vm_swappiness
。所以现在,变量" swappiness"被设置为等于" vm_swappiness"被设置为的值。
int swappiness = mem_cgroup_swappiness(memcg);
在同一个源代码文件中,我们看到了以下内容:
/ * *交换率为100时,匿名和文件具有相同的优先级。 *此扫描优先级实质上是IO成本的倒数。 * / anon_prio =swappiness; file_prio = 200 anon_prio;
那很有意思。从" swappiness"导出两个不同的值。 " anon_prio"和" file_prio"变量保存这些值。随着一个增加,另一个减少,反之亦然。
Linux swappiness值实际上设置两个值之间的比率。
黄金分割
如果释放了该内存,文件页面上的数据可以很容易地检索到。 Linux可以再次读取文件。如我们所见,如果在RAM中更改了文件数据,则必须先将这些更改写入文件,然后才能释放文件页面。但是,无论哪种方式,都可以通过从文件中读取数据来重新填充RAM中的文件页面,那么为什么还要麻烦将这些页面添加到交换分区或者交换文件中呢?如果再次需要该数据,则最好从原始文件读回,而不是从交换空间中读取冗余副本。因此文件页面不会存储在交换中。它们被存储回原始文件中。
对于匿名页面,没有与内存中的值关联的基础文件。这些页面中的值已动态到达。我们不能简单地从文件中读回它们。可以恢复匿名页面内存值的唯一方法是在释放内存之前将数据存储在某处。这就是交换的内容。我们将需要再次引用的匿名页面。
但是请注意,对于文件页面和匿名页面而言,释放内存可能都需要对硬盘进行写操作。如果文件页面数据或者匿名页面数据自上次写入文件或者交换以来已更改,则需要写入文件系统。要检索数据,将需要读取文件系统。两种类型的页面回收都是昂贵的。尝试通过最小化匿名页面的交换来减少硬盘驱动器的输入和输出,只会增加处理写入文件和从文件读取的文件页面所需的硬盘驱动器输入和输出的数量。
从最后的代码片段中可以看到,有两个变量。一个叫file_prio
表示文件优先级,另一个叫anon_prio
表示匿名优先级。
anon_prio
变量设置为Linux swappiness值。" file_prio"值设置为200减去" anon_prio"值。
这些变量包含可协同工作的值。如果它们都设置为100,则它们相等。对于其他任何值,anon_prio
将从100减小到0,file_prio
将从100增大到200.这两个值被送入一个复杂的算法中,该算法确定Linux内核是否在优先使用回收的情况下运行(释放)文件页面或者匿名页面。
我们可以将file_prio
视为系统释放文件页面的意愿,将anon_prio
视为系统释放匿名页面的意愿。这些值不执行的操作是设置何时要使用交换的任何触发器或者阈值。那是在其他地方决定的。
但是,当需要释放内存时,回收和交换算法会考虑这两个变量及其之间的比率,以确定优先考虑释放的页面类型。这决定了相关的硬盘驱动器活动是处理文件页面的文件还是交换匿名页面的空间。
交换实际何时插入?
我们已经确定,Linux swappiness值为将要扫描潜在回收的内存页面类型设置首选项。很好,但是必须决定何时进行交换。
每个存储区都有一个高水位线和一个低水位线。这些是系统派生的值。它们是每个区域中RAM的百分比。这些值用作交换触发阈值。
要检查最高水位线和最低水位线,请使用以下命令在/ proc / zoneinfo
文件中查找:
less /proc/zoneinfo
每个区域将具有一组以页为单位测量的内存值。这是测试计算机上DMA32区域的值。低水位线是13966页,高水位线是16759页:
在正常运行条件下,当区域中的可用内存降到该区域的低水位线以下时,交换算法会考虑anan_prio和file_prio的相对值,开始扫描内存页面以寻找可以回收的内存。
如果Linux swappiness值设置为零,则当文件页面和空闲页面的总值小于高水位线时发生交换。
因此,我们可以看到我们无法使用Linux swappiness值来影响交换在RAM使用方面的行为。就是那样行不通。
Swapiness应该设置为什么?
这取决于硬件,工作负载,硬盘驱动器类型,以及计算机是台式机还是服务器。显然,这不会是一种适合所有类型设置的尺寸。
而且我们必须牢记,交换不只是一种在内存空间不足时释放RAM的机制,交换是功能良好的系统的重要组成部分,如果没有交换,则明智的内存管理将变成Linux很难实现。
更改Linux swappiness值具有立竿见影的效果。我们无需重启。因此,我们可以进行一些小的调整并监视效果。理想情况下,我们需要花几天的时间在计算机上进行不同类型的活动,以尽力找到最理想的设置。
这些是要考虑的几点:
通过将Linux swappiness值设置为零来尝试禁用交换,只会将与交换相关的硬盘驱动器活动转移到与文件相关的硬盘驱动器活动。
如果我们有老化的机械硬盘驱动器,则可以尝试降低Linux swappiness值以偏向匿名页面回收并减少交换分区流失。当然,当我们调低一个设置时,另一设置会增加。减少交换搅动可能会增加文件系统搅动。但是计算机可能更乐于采用一种方法而不是另一种方法。确实,唯一可以肯定的方法就是尝试观察。
对于单用途服务器,例如数据库服务器,我们可以从数据库软件的供应商处获得指导。通常,这些应用程序具有自己专用的文件缓存和内存管理例程,我们最好依靠它们。软件提供商可能会根据计算机规范和工作负载建议Linux交换值。
对于拥有合理最新硬件的普通台式机用户?保持原状。
如何设置Linux Swappiness值
在更改交换值之前,我们需要知道其当前值是多少。如果我们想减少一点,那么这个问题比什么还少吗?我们可以使用以下命令查找:
cat /proc/sys/vm/swappiness
要配置swappiness值,请使用sysctl命令:
sudo sysctl vm.swappiness=45
立即使用新值,无需重新启动。
实际上,如果我们重新启动,则swappiness值将恢复为其默认值60。完成实验并确定要使用的新值后,可以通过将其添加到/ etc / sysctl.conf
文件。我们可以使用任何喜欢的编辑器。使用以下命令通过nano
编辑器编辑文件:
sudo nano /etc/sysctl.conf
当nano
打开时,滚动到文件底部并添加此行。我们使用35作为永久交换值。我们应该替换我们要使用的值。
vm.swappiness=35
要保存更改并退出" nano",请按Ctrl + O,按Enter,然后按Ctrl + Z。
内存管理很复杂
内存管理很复杂。这就是为什么对于一般用户而言,通常最好将其留给内核。
容易想到我们使用的RAM比实际更多。诸如" top"和" free"之类的实用工具可能会给人留下错误的印象。 Linux将把可用的RAM用于各种用途,例如磁盘缓存。这人为地提高了已用存储空间并减少了可用存储空间。实际上,用作磁盘缓存的RAM被标记为已使用和可用,因为它可以随时非常快地回收。