我以某种方式碰巧换出了14 GB的内存。杀死了罪魁祸首之后,我又有了大量的可用内存,因此我想我可以再次引入重要数据。因此,使用32 GB中的5 GB和14 GB的交换空间,我运行了swapoff -a...。4小时后,大约完成了一半的工作。

这意味着不到1 MB / s,而我可以轻松复制200 MB / s。我的交换是加密的,但是所有普通分区也是加密的,而使用es-ni不会导致明显的CPU负载(填充交换空间仅花费了几分钟)。我看到没有优化swapoff的特殊原因,但是我想知道它怎么会这么慢?交换4个硬盘中的每一个上的空间(肯定太过分了,但是谁在乎?)整个交换空间可以在不到5分钟的时间内被(解密并)读取:然而,读取它的1/10大约要花100倍的时间。通过LED)。我还看到交换空间被一个接一个地关闭。

评论

我想知道,当系统将交换的页面单独加载回RAM时,是否会出现相同的现象?例如,如果我将一个系统挂在磁盘上然后启动,则所有内容都被换出,然后将其加载回RAM。对我来说似乎也很慢。

是否所有交换设备都具有相同的优先级?

@PetrPudlák:挂到磁盘有点不同,它只是将RAM内容写入交换区域中的可用空间,而这个(和未挂起的)速度可能要快得多。我无法尝试,因为它不适用于加密交换。

@Nils:是的,优先级是相同的,磁盘及其分区也是如此。

这使它更加奇怪。在这种情况下,交换将在所有磁盘上进行条带化-这应该非常快。交换期间,iostat -d 5也显示磁盘上的IO低吗?

#1 楼

首先,让我们看一下您对硬盘的期望。您的硬盘驱动器可以顺序执行200 MB / s。当您考虑搜索时间时,它可能会慢得多。举一个任意的例子,看看希捷最新的3TB磁盘ST3000DM001的规格:


最大持续数据传输速率:210 MB / s
求平均值读取:<8.5 ms
每个扇区的字节数:4,096

如果您永远不需要查找,并且如果交换位置在磁盘边缘附近,则可以期待最大数量速率= 210 MB / s

但是,如果交换数据完全分散,在最坏的情况下,您需要四处寻找读取的每个扇区。这意味着您每8.5毫秒只能读取4 KB或4 KB / 0.0085 = 470 KB / s就是说,swapoff的运行速度如此之慢,不得不读取乱序的页面,尤其是如果它们被快速写入(这意味着按顺序排列),这似乎很愚蠢。 。但这可能只是内核的工作方式。 Ubuntu错误报告#486666讨论了相同的问题:

The swap is being removed at speed of 0.5 MB/s, while the
hard drive speed is 60 MB/s;
No other programs are using harddrive a lot, system is not under
high load etc.

Ubuntu 9.10 on quad core.

Swap partition is encrypted.
Top (atop) shows near 100% hard drive usage
  DSK | sdc | busy 88% | read 56 | write 0 | avio 9 ms |
but the device transfer is low (kdesysguard)
  0.4 MiB/s on /dev/sdc reads, and 0 on writes


答复之一是:

It takes a long time to sort out because it has to rearrange and flush the
memory, as well as go through multiple decrypt cycles, etc. This is quite
normal


错误报告已关闭,尚未解决。

Mel Gorman的书“了解Linux虚拟内存管理器”虽然有点过时了,但也同意这是一个缓慢的操作:


负责停用区域的功能可以预见地
足够,称为sys_swapoff()。此功能主要与
更新swap_info_struct有关。 try_to_unuse()的职责是在每个已分页的页面中进行分页,这是非常昂贵的。


从2007年开始,关于主题为“加快交换速度”的linux-kernel邮件列表-尽管他们讨论的速度比您看到的要高。


这是一个很有趣的问题,因为swapoff很少使用,因此可能会被普遍忽略。我认为,如果您真的想对其进行跟踪,则第一步是尝试更仔细地观察磁盘使用模式(也许使用atopiostat或什至更强大的工具,例如perfsystemtap)。要寻找的东西可能是过度查找,小的I / O操作,不断重写和移动数据等。

评论


很好的解释。应该注意的是,有可能通过核心转储大部分交换的内存来避免大部分碎片并快速释放大部分交换:unix.stackexchange.com/questions/254202/…

–布兰登·杜普雷(Brandon DuPree)
16年1月14日下午5:21

这不仅是碎片/寻求时间。我的交换是在SSD上进行的,并且随机读取非常快,但是swapoff命令比它应该的慢得多,并且我的SSD负载利用率约为1%。我怀疑内核或交换区(使用约90-100%CPU)中涉及某个列表遍历。当然,如果所有工作都按顺序完成,并且磁盘搜索速度也很慢,则可能会明显增加。

–托马斯·盖奥特·西内斯特(Thomas Guyot-Sionnest)
19-4-24在17:12



#2 楼

我的SSD笔记本电脑也遇到了同样的问题,因此寻找时间应该不是问题。

我找到了另一种解释。这是摘录


现在的工作方式,swapoff在swap分区中查看每个交换出的内存页面,并尝试查找使用该内存的所有程序。如果
无法立即找到它们,它将查看正在运行的每个程序的页面表来查找它们。在最坏的情况下,它会
检查分区中每个换出的页面的所有页面表。
是的-一次又一次地检查相同的页面表。


所以这是一个内核问题,而不是其他任何问题。

评论


不,这不是内核问题恕我直言。这是实现交换的方式。当换出的进程退出时,不需要花费很长时间。

– Marki555
15年1月22日在14:05

这是内核中实现swapoff的问题-因此是内核问题!您可以看到是否可以跟踪swapoff,那么它所做的几乎所有事情就是调用swapoff系统调用。

–尼克·克雷格·伍德
15年1月22日在15:51

我的服务器确实具有48 GB RAM(32核),曾使用6 GB的免费错误交换(0.7 GB)。 swappiness = 10,尝试将其设置为0,还尝试了swapoff以查看会发生什么。 swapoff花费了很长时间(可能需要30分钟),释放了极慢的速度。我确实在几乎没有负载的情况下具有SSD,并且CPU相似,期望交换过程需要100%的CPU。

–索林
15年1月23日在12:25

问题是如何实现交换(在内核中)。几年前,关于内核开发中更好的方法的讨论,但是他们说这是一个极端的案例,不想改变它。

– Marki555
15年1月26日在23:17

在具有1 TB RAM(是,TB)和2 GB交换(要求SAP的情况)的服务器上,交换花费了12个小时才能释放出2 GB的5%(1个CPU核心为100%)。

– Marki555
15年1月26日在23:19

#3 楼

是的,swapoff机制效率极低。解决方法很简单:遍历进程,而不是遍历交换的页面。使用以下python脚本(我不隶属于):

 git clone https://github.com/wiedemannc/deswappify-auto
cd ./deswappify-auto
sudo python3 deswappify_auto.py -d -v info
 


请注意,守护程序模式仅适用于经常休眠的台式机/笔记本电脑。我不会在服务器系统上将其作为守护程序运行-只需运行一段时间,等它报告已处理了一些进程,然后停止并尝试:

swapoff /dev/x


由于大多数页面现在都存在于交换和内存中,因此swapoff几乎没有什么工作,现在应该非常快(我看到数百MB / s)。

前面的历史部分

前面提到的python脚本基于此答案的其余部分,这又是我对jlong​​编写的较旧答案的改进。由于脚本要安全得多,因此我建议仅尝试将其余答案作为最后一道防线:实际执行任何操作,只列出前10个内存段(实际上它打印出更多的单行代码;是的,我确实喜欢单行代码;只检查命令,接受风险,复制并粘贴到您的shell中;这些实际上将从交换读取) )。

perl -we 'for(`ps -e -o pid,args`) { if(m/^ *(\d+) *(.{0,40})/) { $pid=; $desc=; if(open F, "/proc/$pid/smaps") { while(<F>) { if(m/^([0-9a-f]+)-([0-9a-f]+) /si){ $start_adr=; $end_adr=; }  elsif(m/^Swap:\s*(\d\d+) *kB/s){ print "SSIZE=_kB\t gdb --batch --pid $pid -ex \"dump memory /dev/null 0x$start_adr 0x$end_adr\"\t2>&1 >/dev/null |grep -v debug\t### $desc \n" }}}}}' | sort -Vr | head


主要的一线安全(对我而言)是安全的,但它读取了很多/ proc。

-为您的手动检查准备的命令并不安全。在从交换读取内存段的过程中,每个命令都将挂起一个进程。因此,对于不能容忍任何暂停的流程而言,这是不安全的。我看到的传输速度约为每分钟1 GB。 (前面提到的python脚本消除了该缺陷)。

另一个危险是给系统带来过多的内存压力,因此请使用常见的free -m检查。 br />
...Paste the generated one-liners...
swapoff /your/swap    # much faster now


这个perl脚本的输出是一系列gdb命令dump memory (range),它们将交换的页面重新调用到内存中。按大小(SSIZE)。 | sort -Vr | head代表适合版本号的排序,但是它可以满足我的目的。我不知道如何进行数字排序。

评论


您可以在此处使用数字排序,并使用-t = -k 2n

–StéphaneChazelas
16-11-24在17:02

似乎没有必要使用gdb来查看进程内存(至少在最近的内核上)。可以只打开/ proc / $ pid / mem,直接查找和阅读。以下是基于您的摘录的PoC:gist.github.com/WGH-/91260f6d65db88be2c847053c49be5ae这种方式不会停止,AFAIK不会因此而造成任何危险。

– WGH
17-10-20在0:13



@WGH我已经根据您的方法放了一个脚本。我最初的答案很复杂。

– Kubanczyk
20-4-29在20:14



#4 楼

在交换期间,如果检测到使用中的交换插槽,则内核首先在页面中交换。然后,函数unuse_process()尝试查找与刚交换的页面相对应的所有页面表条目,并对页面表进行必要的更新。搜索是详尽且耗时的:它访问(整个系统的)每个内存描述符,并逐一检查其页表条目。

请参考“了解Linux内核3rd版本”的第724页。