Kiedy mój system Linux zbliża się do stronicowania (tj. W moim przypadku 16 GB pamięci RAM jest prawie pełny, 16 GB zamiany jest całkowicie pusty), jeśli nowy proces X próbuje przydzielić część pamięci, system całkowicie się blokuje. To znaczy, dopóki nieproporcjonalnie duża liczba stron (wrt całkowity rozmiar i szybkość żądań alokacji pamięci X) zostały zamienione. Zauważ, że nie tylko gui całkowicie przestaje odpowiadać, ale nawet podstawowe usługi, takie jak sshd, są całkowicie zablokowane.
Są to dwa fragmenty kodu (co prawda surowe), których używam do wywołania tego zachowania w bardziej „naukowy” sposób. Pierwsza pobiera dwie liczby x, y z wiersza poleceń i przechodzi do przydzielania i inicjowania wielu porcji y bajtów, dopóki nie zostanie przydzielonych więcej niż x bajtów ogółem. A potem po prostu śpi w nieskończoność. Będzie to wykorzystane do doprowadzenia systemu na skraj stronicowania.
#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;
}
Drugi fragment kodu robi dokładnie to samo, co pierwszy, z wyjątkiem tego, że ma sleep(1);
zaraz po printf
(nie powtórzę całego kodu). Ten będzie używany, gdy system jest na krawędzi stronicowania, aby wymieniać strony w „łagodny” sposób, tj. Powoli żądając przydziału nowych fragmentów pamięci (tak, aby system z pewnością był w stanie wymieniać strony i nadążaj za nowymi żądaniami).
Tak więc, po skompilowaniu dwóch fragmentów kodu, nazwijmy odpowiedni exes fasteater i powolny, zróbmy to:
1) uruchom swoje ulubione GUI (oczywiście nie jest to absolutnie konieczne)
2) uruchom miernik mem / swap (np. watch -n 1 free
)
3) uruchom wiele instancji, fasteater x y
gdzie x jest rzędu gigabajtów, a y jest rzędu megabajtów. Rób to, aż prawie wypełnisz barana.
4) uruchom jedno wystąpienie sloweater x y
, gdzie x jest rzędu gigabajtów, a y jest rzędu megabajtów.
Po kroku 4), co powinno się zdarzyć (i zawsze tak się dzieje w moim systemie) jest to, że zaraz po wyczerpaniu pamięci RAM, system zablokuje się całkowicie. GUI jest zablokowane sshd jest zablokowane itp. ALE, nie na zawsze! Po zakończeniu żądania przydzielenia przez system Sloweater system powróci do życia (po minutach blokowania, a nie sekundach ...) w tej sytuacji:
a) baran jest prawie pełny
b) zamiana jest również pełna (pamiętaj, że na początku była pusta)
c) brak interwencji zabójcy.
I zauważ, że partycja wymiany znajduje się na dysku SSD. Wygląda więc na to, że system nie jest w stanie stopniowo przenosić stron z pamięci ram do swap (prawdopodobnie z fasteaterów, które właśnie śpią), aby zrobić miejsce dla powolnych (i zaledwie kilku megabajtów) żądań wolnej wody.
Teraz ktoś mnie poprawi, jeśli się mylę, ale nie wydaje się, że tak powinien wyglądać nowoczesny system w tym otoczeniu. Wygląda na to, że zachowuje się jak stare systemy (z powrotem waaaaay), kiedy brak było stronicowania, a system pamięci wirtualnej po prostu zamienił całą przestrzeń pamięci jakiegoś procesu zamiast kilku stron.
Czy ktoś może to również przetestować? A może ktoś, kto ma również system BSD.
AKTUALIZACJA 1
Postępowałem zgodnie z radą Marka Plotnicka w komentarzach i zacząłem vmstat 1 >out
przed przystąpieniem do testu stronicowania. Możesz zobaczyć wynik poniżej (przecinam całą początkową część, w której RAM jest wypełniony bez udziału zamiany):
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
Jak widać, jak tylko zaangażowana jest zamiana, następuje masowa zamiana 15916880 kilobajtów naraz, która, jak sądzę, trwa przez cały czas zawieszenia systemu. Wszystko to jest najwyraźniej spowodowane procesem (wolniejszym), który prosi o 10 MB co sekundę.
AKTUALIZACJA 2: Zrobiłem szybką instalację FreeBSD i powtórzyłem ten sam schemat alokacji jak w Linuksie ... i był tak płynny, jak powinien. FreeBSD zamieniał strony stopniowo, podczas gdy wolniejszy komputer przydzielał wszystkie swoje 10 MB fragmentów pamięci. Ani jednego zaczepu ... WTF tu się dzieje ?!
AKTUALIZACJA 3: Złożyłem błąd w module śledzenia błędów jądra. Wygląda na to, że przyciąga uwagę, więc ... kciuki ...
vmstat 1>somefile
bezpośrednio z systemu, a następnie zobaczyć, co zgłasza po przywróceniu systemu. Spróbuję tego.
swappiness
jest domyślną wartością 60 (nie to, że jej zmiana daje lepszy wynik). Jądro używane z vmstat
uruchomieniem to 4.14.35, ale próbowałem 4.15, 4.16 i nawet wróciłem do serii 4.0 (!): Zawsze takie samo zachowanie. I to nie jest tak, że używam dziwnej dystrybucji, to tylko debian. Nie używam obrazów jądra z Debiana (nie że moje mają nietypowe konfiguracje), ale próbowałem jednego z tych ... takich samych zachowań.