Est-ce ainsi que la pagination Linux devrait se comporter?


26

Lorsque mon système Linux se rapproche de la pagination (c'est-à-dire, dans mon cas, 16 Go de RAM presque plein, 16 Go de swap complètement vide) si un nouveau processus X essaie d'allouer de la mémoire, le système se verrouille complètement. Autrement dit, jusqu'à ce qu'un nombre disproportionné de pages (par rapport à la taille totale et au taux des demandes d'allocation de mémoire de X) aient été échangées. Notez que non seulement l'interface graphique ne répond plus complètement, mais même les services de base comme sshd sont complètement bloqués.

Ce sont deux morceaux de code (certes grossiers) que j'utilise pour déclencher ce comportement de manière plus "scientifique". Le premier obtient deux nombres x, y à partir de la ligne de commande et continue d'allouer et d'initialiser plusieurs morceaux de y octets jusqu'à ce que plus de x octets totaux aient été alloués. Et puis il dort juste indéfiniment. Cela sera utilisé pour amener le système au bord de la pagination.

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

Le deuxième morceau de code fait exactement ce que le premier fait, sauf qu'il a un sleep(1);droit après le printf(je ne vais pas répéter tout le code). Celui-ci sera utilisé lorsque le système est sur le point de paginer pour le faire échanger des pages d'une manière "douce", c'est-à-dire en demandant lentement l'allocation de nouveaux morceaux de mémoire (de sorte que le système devrait certainement être en mesure d'échanger des pages et suivre les nouvelles demandes).

Donc, avec les deux morceaux de code compilés, appelons les exes respectifs fasteater et sloweater, faisons ceci:

1) Commencez votre interface graphique préférée (pas strictement nécessaire bien sûr)

2) démarrer un compteur mem / swap (par exemple watch -n 1 free)

3) démarrer plusieurs instances fasteater x yoù x est de l'ordre des gigaoctets et y est de l'ordre des mégaoctets. Faites-le jusqu'à ce que vous remplissiez presque le bélier.

4) démarrer une instance de sloweater x y, où x est de l'ordre des gigaoctets et y est de l'ordre des mégaoctets.

Après l'étape 4), ce qui devrait arriver (et cela arrive toujours pour mon système), c'est que juste après avoir épuisé le vérin, le système se verrouille complètement. gui est verrouillé sshd est verrouillé etc. MAIS, pas pour toujours! Une fois que le ralentisseur a terminé ses demandes d'allocation, le système reprendra vie (après des minutes de verrouillage, pas des secondes ...) avec cette situation:

a) le bélier est à peu près plein

b) le swap est aussi à peu près plein (rappelez-vous, il était vide au début)

c) aucune intervention de tueur.

Et notez que la partition de swap se trouve sur un SSD. Ainsi, le système semble incapable de déplacer progressivement les pages du bélier vers le swap (vraisemblablement des fasteaters qui ne font que dormir) pour faire de la place aux demandes lentes (et de quelques mégaoctets seulement) du sloweater.

Maintenant, quelqu'un me corrige si je me trompe, mais cela ne semble pas la façon dont un système moderne devrait se comporter dans ce contexte. Il semble se comporter comme les anciens systèmes (waaaaay back) quand il n'y avait pas de support pour la pagination et le système de mémoire virtuelle a juste échangé tout l'espace mémoire d'un processus au lieu de quelques pages.

Quelqu'un peut-il tester cela aussi? Et peut-être quelqu'un qui a également un système BSD.

MISE À JOUR 1 J'ai suivi les conseils de Mark Plotnick ci-dessous dans les commentaires et j'ai commencé vmstat 1 >outavant de procéder au test de radiomessagerie. Vous pouvez voir le résultat ci-dessous (j'ai coupé toute la partie initiale où le bélier est rempli sans implication de swap):

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

Comme vous pouvez le voir, dès que le swap est impliqué, il y a un swapout massif de 15916880 Kbytes à la fois qui, je suppose, dure pendant toute la durée du gel du système. Et tout cela est apparemment causé par un processus (le sloweater) qui ne demande que 10 Mo par seconde.

MISE À JOUR 2: J'ai fait une installation rapide de FreeBSD et j'ai répété le même schéma d'allocation utilisé avec Linux ... et c'était aussi fluide qu'il devrait l'être. FreeBSD a échangé les pages progressivement tandis que le sloweater a alloué tous ses morceaux de mémoire de 10 Mo. Pas un accroc du tout ... WTF se passe ici?!

MISE À JOUR 3: J'ai déposé un bug avec le bugtracker du noyau. Il semble attirer l'attention, alors ... croise les doigts ...


2
Comme je l'ai mentionné, tout est verrouillé. J'ai essayé ssh'ing d'un autre système, il arrive juste à expiration.
John Terragon

2
Si je démarre vmstat 1 avec une sortie stdout, je pense que ça va geler. Mais vous avez raison, je pourrais simplement commencer vmstat 1>somefiledirectement à partir du système et voir ce qu'il signale une fois que le système est revenu à la vie. Je vais essayer ça.
John Terragon

2
J'ai utilisé vmstat. Résultats dans la mise à jour ci-dessus.
John Terragon

3
swappinessest le 60 par défaut (pas que le changer donne un meilleur résultat). Le noyau utilisé avec la vmstatcourse est 4.14.35 mais j'ai essayé 4.15, 4.16 et je suis même revenu à la série 4.0 (!): Toujours le même comportement. Et ce n'est pas que j'utilise une distribution bizarre, c'est juste Debian. Je n'utilise pas les images du noyau de Debian (pas que les miennes aient des configurations inhabituelles) mais j'ai essayé l'une de ces ... même comportement.
John Terragon

2
Discussion très intéressante sur le bug du noyau! Et il semble que vous ayez isolé ce problème pour échanger une partition chiffrée avec LUKS. Vous voudrez peut-être modifier votre réponse ou éventuellement publier une réponse vous-même (avec les solutions de contournement connues jusqu'à présent, et peut-être continuer à la mettre à jour à mesure que la discussion LKML obtient des résultats plus concluants.) Vraiment impressionnant de voir la communauté du noyau Linux à l'œuvre! 😁
filbranden

Réponses:


1

C'est exactement pour cela que la protection anti-thrash existe.

Il surveille constamment l'état de permutation et, lorsque quelque chose commence accidentellement à occuper beaucoup de RAM, gèle temporairement les processus gourmands en RAM, de sorte que le noyau a le temps de permuter de la mémoire sans que le système entier ne réponde pas.


-3

Vous allouez uniquement de la mémoire - vous n'y mettez rien. Un programme "normal" allouerait un morceau puis commencerait à l'utiliser. L'allocation n'est pas la même chose que l'utilisation de la mémoire.


3
Bienvenue à publier sur Unix StackExchange. Il y met des données, ces données se trouvent être nulles. Voir le memset (). Le noyau Linux fournit une page physique de RAM dès que vous écrivez sur la page virtuelle; il ne regarde pas la valeur spécifique qui est écrite.
sourcejedi

En fait, j'ai compilé et exécuté cela sur mon bureau à partir de 2 Go utilisés, 6 Go gratuits. Il a en fait échangé à un rythme lent au départ et ce n'est que lorsqu'il a atteint la limite qu'il a été échangé de manière agressive - ce qui a ensuite provoqué le blocage de diverses actions de l'interface graphique.
Jeremy Boden
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.