这是Linux分页应该如何表现吗?


26

当我的Linux系统接近分页时(例如,在我的情况下,16GB的内存几乎已满,16GB的交换空间完全为空),如果新进程X尝试分配一些内存,系统将完全锁定。也就是说,直到不成比例的页面(已浪费X的内存分配请求的总大小和速率)为止。请注意,不仅gui变得完全没有响应,甚至sshd之类的基本服务也被完全阻止。

这是我用来以更“科学”的方式触发此行为的两段代码(当然是粗糙的)。第一个从命令行获取两个数字x,y,然后继续分配和初始化y字节的多个块,直到分配了x个以上的总字节。然后无限期地睡觉。这将使系统处于分页的边缘。

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>

int main(int argc, char** argv) {
   long int max = -1;
   int mb = 0;
   long int size = 0;
   long int total = 0;
   char* buffer;

   if(argc > 1)
     {
       max = atol(argv[1]);
       size = atol(argv[2]);
     }
   printf("Max: %lu bytes\n", max);
   while((buffer=malloc(size)) != NULL && total < max) {
       memset(buffer, 0, size);
       mb++;
       total=mb*size;
       printf("Allocated %lu bytes\n", total);       
   }      
   sleep(3000000);
   return 0;
}

第二段代码的功能与第一段代码完全相同,只是第二段代码sleep(1);后面有一个权重printf(我将不重复整个代码)。当系统处于页面调度的边缘时,将使用此选项,以使它以“温和”的方式换出页面,即通过缓慢地请求分配新的内存块(因此系统当然应该能够换出页面)并跟上新的要求)。

因此,在编译了两段代码之后,我们将它们分别称为fasteater和sloweater,让我们这样做:

1)启动您最喜欢的GUI(当然并非绝对必要)

2)启动一些内存/交换表(例如watch -n 1 free

3)启动多个实例,fasteater x y其中x为千兆字节,而y为兆字节。做到这一点,直到你几乎填满了公羊。

4)启动的一个实例sloweater x y,其中x的大小为千兆字节,y的大小为兆字节。

在第4步之后,应该发生的事情(并且对于我的系统来说总是如此)是在用尽柱塞之后,系统将完全锁定。gui被锁定sshd被锁定等。但是,不是永远!在sloweater完成分配请求后,系统将在这种情况下恢复运行(锁定几分钟后,而不是几秒钟...):

a)公羊快满了

b)交换也即将满(请记住,开始时是空的)

c)不得使用任何杀手oom。

并注意交换分区在SSD上。因此,系统似乎无法将页面从ram逐渐移到交换(大概是从刚刚休眠的Fasteater)来为缓慢的(且只有几兆字节)请求腾出空间。

现在,如果我错了,有人会纠正我,但这似乎不是现代系统在这种情况下的表现方式。当不支持分页并且虚拟内存系统只交换了某个进程的整个内存空间而不是几页时,它的行为似乎与旧系统类似(回过头来)。

有人也可以测试吗?也许有人也拥有BSD系统。

UPDATE 1 我遵循了Mark Plotnick在下面的注释中的建议,并且vmstat 1 >out在进行分页测试之前就开始了。您可以在下面看到结果(我切割了填充RAM的整个初始部分,而没有交换介入):

procs -----------memory---------- ---swap-- -----io---- -system-- ------cpu-----
r  b   swpd   free   buff  cache   si   so    bi    bo   in   cs us sy id wa st
0  0   6144 160792      8 272868    0    0     0     0  281 1839  1  0 99  0  0
0  0   6144 177844      8 246096    0    0     0     0  425 2300  1  1 99  0  0
0  0   6144 168528      8 246112    0    0    16     0  293 1939  1  0 99  0  0
0  0   6144 158320      8 246116    0    0     0     0  261 1245  0  0 100  0  0
2  0  10752 161624      8 229024    0 4820 17148  4820  845 3656  1  2 97  0  0
2  0  10752 157300      8 228096    0    0 88348     0 2114 8902  0  5 94  1  0
0  0  10752 176108      8 200052    0    0 108312     0 2466 9772  1  5 91  3  0
0  0  10752 170040      8 196780    0    0 17380     0  507 1895  0  1 99  0  0
0 10  10752 160436      8 191244    0    0 346872    20 4184 17274  1  9 64 26  0
0 29 12033856 152888      8 116696 5992 15916880 1074132 15925816 819374 2473643  0 94  0  6  0
3 21 12031552 295644      8 136536 1188    0 11348     0 1362 3913  0  1 10 89  0
0 11 12030528 394072      8 151000 2016    0 17304     0  907 2867  0  1 13 86  0
0 11 12030016 485252      8 158528  708    0  7472     0  566 1680  0  1 23 77  0
0 11 12029248 605820      8 159608  900    0  2024     0  371 1289  0  0 31 69  0
0 11 12028992 725344      8 160472 1076    0  1204     0  387 1381  0  1 33 66  0
0 12 12028480 842276      8 162056  724    0  3112     0  357 1142  0  1 38 61  0
0 13 12027968 937828      8 162652  776    0  1312     0  363 1191  0  1 31 68  0
0  9 12027456 1085672      8 163260  656    0  1520     0  439 1497  0  0 30 69  0
0 10 12027200 1207624      8 163684  728    0   992     0  411 1268  0  0 42 58  0
0  9 12026688 1331492      8 164740  600    0  1732     0  392 1203  0  0 36 64  0
0  9 12026432 1458312      8 166020  628    0  1644     0  366 1176  0  0 33 66  0

如您所见,只要涉及交换,就会立即有15916880 KB的大量交换,我猜想这将在整个系统冻结期间持续。所有这些显然是由一个进程(缓慢的进程)引起的,该进程仅每秒请求10MB。

更新2:我快速安装了FreeBSD,并重复了Linux所用的相同分配方案……并且它应该尽可能地顺畅。FreeBSD逐渐交换了页面,而缓慢者分配了所有10MB的内存。没有任何障碍... WTF正在这里进行?!

更新3:我向内核bugtracker 提交了一个bug。似乎受到了关注,所以...手指交叉...


2
正如我提到的,所有内容均已锁定。我尝试从另一个系统ssh'ing只是超时。
约翰·特拉贡

2
如果我用stdout输出启动vmstat 1,我认为它将冻结。但是您是对的,我可以vmstat 1>somefile直接从系统开始,然后在系统恢复运行后查看其报告。我会尝试的。
约翰·特拉贡

2
我使用了vmstat。结果在上面的更新中。
John Terragon

3
swappiness是默认的60(不是更改它会带来更好的结果)。vmstat运行时使用的内核是4.14.35,但是我尝试了4.15、4.16,甚至还回到了4.0系列(!):始终是相同的行为。这并不是说我正在使用一些奇怪的发行版,而仅仅是debian。我不使用来自debian的内核映像(不是我的具有不寻常的配置),但是我尝试了其中一种...相同的行为。
John Terragon

2
关于内核错误的非常有趣的讨论!看起来您隔离了此问题,以交换使用LUKS加密的分区。您可能想要编辑您的答案或自己发布答案(使用到目前为止已知的解决方法,并且随着LKML讨论获得更多结论性结果,可能会不断对其进行更新。)看到Linux内核社区正在工作,真令人印象深刻!😁–
filbranden

Answers:


1

这正是存在thrash-protect的目的。

它会持续监视交换状态,并在意外开始占用大量RAM时暂时冻结RAM贪婪进程,因此内核有时间交换一些内存,而不会导致整个系统无响应。


-3

您只分配内存-实际上没有在其中分配任何内容。一个“普通”程序将分配一个块,然后开始使用它。分配与内存使用情况不同。


3
欢迎来到Unix StackExchange上发帖。它确实将数据放入其中,而该数据恰好为零。请参阅memset()。一旦您写入虚拟页面,Linux内核就会提供一个物理RAM页面。它不会查看写入的特定值。
sourcejedi

实际上,我在桌面上编译并运行了该文件,最初使用2GB,6GB免费。实际上,它最初的交换速度很慢,并且只有在达到极限时才积极交换-然后导致各种GUI动作被占用。
杰里米·博登
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.