Sollte sich Linux-Paging so verhalten?

26

Wenn sich mein Linux-System dem Paging nähert (in meinem Fall 16 GB RAM fast voll, 16 GB Swap vollständig leer), wird das System durch einen neuen Prozess X beim Versuch, Speicher zuzuweisen, vollständig gesperrt. Das heißt, bis eine unverhältnismäßig große Anzahl von Seiten (bezogen auf die Gesamtgröße und Rate der Speicherzuweisungsanforderungen von X) ausgelagert wurde. Beachten Sie, dass nicht nur die Benutzeroberfläche nicht mehr reagiert, sondern auch grundlegende Dienste wie sshd vollständig blockiert werden.

Dies sind zwei Code-Teile (zugegebenermaßen grob), die ich verwende, um dieses Verhalten auf "wissenschaftlichere" Weise auszulösen. Der erste erhält zwei Zahlen x, y von der Befehlszeile und beginnt mit der Zuweisung und Initialisierung mehrerer Teile von y Bytes, bis mehr als x Gesamtbytes zugewiesen wurden. Und schläft dann einfach auf unbestimmte Zeit. Dies wird verwendet, um das System an den Rand des Paging zu bringen.

#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;
}

Der zweite Teil des Codes macht genau das, was der erste tut, mit der Ausnahme, dass er sleep(1);direkt nach dem steht printf(ich werde nicht den gesamten Code wiederholen). Diese Option wird verwendet, wenn das System kurz vor dem Auslagern steht, um das Auslagern von Seiten auf "sanfte" Weise zu ermöglichen, dh indem langsam die Zuweisung neuer Speicherbereiche angefordert wird (sodass das System auf jeden Fall Seiten auslagern kann und halten Sie sich mit den neuen Anfragen auf dem Laufenden).

Nennen wir also mit den beiden kompilierten Code-Teilen die jeweiligen exes fasteater und sloweater:

1) starte deine Lieblings-GUI (natürlich nicht unbedingt erforderlich)

2) starte ein Mem / Swap Meter (zB watch -n 1 free)

3) Starten Sie mehrere Instanzen von fasteater x yx in der Größenordnung von Gigabyte und y in der Größenordnung von Megabyte. Tun Sie es, bis Sie fast den Widder gefüllt haben.

4) Starten Sie erneut eine Instanz von sloweater x y, wobei x in der Größenordnung von Gigabyte und y in der Größenordnung von Megabyte liegt.

Nach Schritt 4) sollte (und das passiert bei meinem System immer) passieren, dass das System unmittelbar nach dem Entleeren des Stempels vollständig verriegelt wird. gui ist gesperrt sshd ist gesperrt usw. ABER nicht für immer! Nachdem sloweater seine Zuweisungsanforderungen beendet hat, wird das System in der folgenden Situation wieder zum Leben erweckt (nach Minuten des Sperrens, nicht nach Sekunden ...):

a) RAM ist ungefähr voll

b) Swap ist auch ungefähr voll (denken Sie daran, es war am Anfang leer)

c) Keine Mörderintervention.

Beachten Sie, dass sich die Swap-Partition auf einer SSD befindet. Das System scheint also nicht in der Lage zu sein, Seiten schrittweise vom RAM zum Swap zu verschieben (vermutlich von den Fasteatern, die gerade schlafen), um Platz für die langsamen (und nur wenige Megabyte großen) Anforderungen des Sloweaters zu schaffen.

Jetzt korrigiert mich jemand, wenn ich falsch liege, aber dies scheint nicht so zu sein, wie sich ein modernes System in dieser Umgebung verhalten sollte. Es scheint sich wie die alten Systeme zu verhalten (waaaaay back), als es keine Unterstützung für Paging gab und das virtuelle Speichersystem nur den gesamten Speicherplatz eines Prozesses anstelle weniger Seiten ausgelagert hat.

Kann das auch jemand testen? Und vielleicht jemand, der auch ein BSD-System hat.

UPDATE 1 Ich folgte den Ratschlägen von Mark Plotnick in den Kommentaren und begann, vmstat 1 >outbevor ich mit dem Paging-Test fortfuhr. Sie können das Ergebnis unten sehen (ich schneide den gesamten Anfangsteil, in dem der Stößel gefüllt ist, ohne dass ein Austausch erforderlich ist):

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

Wie Sie sehen, gibt es, sobald der Swap involviert ist, einen massiven Swapout von 15916880 KByte auf einmal, der, glaube ich, für die gesamte Dauer des Einfrierens des Systems anhält. Und all dies wird anscheinend durch einen Prozess (den Sloweater) verursacht, der nur 10 MB pro Sekunde benötigt.

UPDATE 2: Ich habe eine schnelle Installation von FreeBSD durchgeführt und das gleiche Zuweisungsschema wie unter Linux wiederholt ... und es war so reibungslos, wie es sein sollte. FreeBSD tauschte die Seiten nach und nach aus, während der Sloweater alle 10-MB-Speicherbereiche zuordnete. Keine einzige Störung ... WTF geht hier vor ?!

UPDATE 3: Ich habe einen Fehler beim Kernel-Bugtracker gemeldet. Es scheint etwas Aufmerksamkeit zu bekommen, also ... Daumen drücken ...

John Terragon
quelle
2
Wie gesagt, alles ist verschlossen. Ich habe versucht, von einem anderen System zu ssh'ing, es läuft gerade aus.
John Terragon
2
Wenn ich vmstat 1 mit stdout-Ausgabe starte, denke ich, dass es einfrieren wird. Aber Sie haben Recht, ich könnte einfach vmstat 1>somefiledirekt vom System aus starten und dann sehen, was es meldet, nachdem das System wieder zum Leben erweckt wurde. Ich werde das versuchen.
John Terragon
2
Ich habe vmstat verwendet. Ergebnisse im Update oben.
John Terragon
3
swappinessist die Standardeinstellung 60 (nicht das Ändern ergibt ein besseres Ergebnis). Der mit dem vmstatLauf verwendete Kernel ist 4.14.35, aber ich habe 4.15, 4.16 ausprobiert und bin sogar auf die 4.0-Serie (!) Zurückgekehrt: immer das gleiche Verhalten. Und es ist nicht so, dass ich eine seltsame Distribution verwende, es ist nur Debian. Ich verwende nicht die Kernel-Images von Debian (nicht meine, die ungewöhnliche Konfigurationen haben), aber ich habe eines davon ausprobiert ... dasselbe Verhalten.
John Terragon
2
Sehr interessante Diskussion über den Kernel Bug! Und es sieht so aus, als hätten Sie dieses Problem isoliert, um mit LUKS verschlüsselte Partitionen auszutauschen. Möglicherweise möchten Sie Ihre Antwort bearbeiten oder selbst eine Antwort veröffentlichen (mit den bisher bekannten Problemumgehungen, und aktualisieren Sie sie möglicherweise ständig, wenn die LKML-Diskussion zu schlüssigeren Ergebnissen führt.) Wirklich beeindruckend, wenn Sie die Linux-Kernel-Community bei der Arbeit sehen! 😁
Filbranden

Antworten:

1

Genau dafür gibt es Thrash-Protect .

Es überwacht ständig den Auslagerungsstatus und friert vorübergehend RAM-gierige Prozesse ein, wenn versehentlich viel RAM belegt wird, sodass der Kernel Zeit hat, Speicher auszulagern, ohne dass das gesamte System nicht mehr reagiert.

bodqhrohro
quelle
-3

Sie ordnen nur Speicher zu - Sie fügen nichts hinzu. Ein "normales" Programm würde einen Block zuordnen und ihn dann verwenden. Die Zuweisung entspricht nicht der Speichernutzung.

Jeremy Boden
quelle
3
Willkommen beim Posten auf Unix StackExchange. Es fügt Daten ein, die zufällig Null sind. Siehe das Memset (). Der Linux-Kernel stellt eine physische Seite des Arbeitsspeichers bereit, sobald Sie auf die virtuelle Seite schreiben. es schaut nicht auf den spezifischen Wert, der geschrieben wird.
Sourcejedi
Eigentlich habe ich dies auf meinem Desktop kompiliert & ausgeführt, beginnend mit 2GB, 6GB frei. Die Auslagerung erfolgte anfangs nur langsam, und erst wenn das Limit erreicht war, wurde die Auslagerung aggressiv durchgeführt - was dann dazu führte, dass verschiedene GUI-Aktionen ausfielen.
Jeremy Boden