Je ne suis pas développeur de noyau mais j'ai passé des années à philosopher sur ce problème parce que je suis tombé sur ce soooo plusieurs fois. En fait, j'ai trouvé une métaphore pour toute la situation, alors laissez-moi vous dire cela. Je suppose dans mon histoire que des choses comme «swap» n'existent pas. Le swap n'a pas beaucoup de sens de nos jours avec 32 Go de RAM.
Imaginez un de vos quartiers où l'eau est raccordée à chaque bâtiment par des canalisations et où les villes doivent gérer la capacité. Supposons que vous n'ayez qu'une production de 100 unités d'eau par seconde (et que toute la capacité inutilisée soit gaspillée parce que vous n'avez pas de réservoirs). Chaque maison (maison = une petite application, un terminal, le widget horloge, etc.) nécessite 1 unité d'eau par seconde. Tout cela est agréable et bon parce que votre population est d'environ 90 personnes, donc tout le monde a assez d'eau.
Maintenant, le maire (= vous) décide que vous souhaitez ouvrir un grand restaurant (= navigateur). Ce restaurant abritera plusieurs cuisiniers (= onglets du navigateur). Chaque cuisinier a besoin d'une unité d'eau par seconde. Vous commencez avec 10 cuisiniers, donc la consommation totale d'eau pour tout le quartier est de 100 unités d'eau, ce qui est toujours bien.
Maintenant, les choses amusantes commencent: vous embauchez un autre cuisinier dans votre restaurant, ce qui rend les besoins en eau totaux 101 que vous n'avez évidemment pas. Tu dois faire quelque chose.
La gestion de l'eau (= noyau) a 3 options.
1. La première option consiste simplement à déconnecter le service pour les maisons qui n'ont pas utilisé l'eau récemment. C'est bien, mais si la maison déconnectée veut utiliser l'eau à nouveau, elle devra recommencer le long processus d'enregistrement. La gestion peut déconnecter plusieurs maisons pour libérer plus de ressources en eau. En fait, ils déconnecteront toutes les maisons qui n'ont pas utilisé d'eau récemment, gardant ainsi une certaine quantité d'eau gratuite toujours disponible.
Bien que votre ville continue de fonctionner, l'inconvénient est que le progrès s'arrête. La plupart de votre temps est consacré à l'attente de la gestion de l'eau pour rétablir votre service.
C'est ce que fait le noyau avec les pages sauvegardées sur fichier. Si vous exécutez un grand exécutable (comme Chrome), son fichier est copié dans la mémoire. Lorsqu'il manque de mémoire ou s'il y a des parties qui n'ont pas été consultées récemment, le noyau peut supprimer ces parties car il peut les recharger de toute façon. Si cela est fait de manière excessive, cela arrête votre bureau car tout attendra simplement les E / S du disque. Notez que le noyau supprimera également beaucoup de pages les moins récemment utilisées lorsque vous commencez à faire beaucoup d'E / S. C'est pourquoi il faut du temps pour passer à une application d'arrière-plan après avoir copié plusieurs fichiers volumineux comme des images DVD.
C'est le comportement le plus ennuyeux pour moi car je déteste les hickups et vous n'avez aucun contrôle sur cela. Ce serait bien de pouvoir l'éteindre. Je pense à quelque chose dans le sens de
sed -i 's/may_unmap = 1/may_unmap = (vm_swappiness >= 0)/' mm/vmscan.c
puis vous pouvez définir vm_swappiness sur -1 pour désactiver cela. Cela a très bien fonctionné dans mes petits tests mais hélas je ne suis pas développeur de noyau donc je ne l'ai envoyé à personne (et évidemment la petite modification ci-dessus n'est pas complète).
2.La direction pourrait refuser la demande d'eau du nouveau cuisinier. Cela semble initialement être une bonne idée. Cependant, il y a deux inconvénients. D'abord, il y a des entreprises qui demandent beaucoup d'abonnements à l'eau même si elles ne les utilisent pas. Une raison possible de le faire est d'éviter tous les frais généraux de parler à la gestion de l'eau chaque fois qu'ils ont besoin d'un peu d'eau supplémentaire. Leur consommation d'eau augmente et diminue en fonction de l'heure de la journée. Par exemple, dans le cas du restaurant, l'entreprise a besoin de beaucoup plus d'eau à midi qu'à minuit. Ils demandent donc toute l'eau possible qu'ils pourraient utiliser, mais cela gaspille les allocations d'eau à minuit. Le problème est que toutes les entreprises ne peuvent pas prévoir correctement leur utilisation de pointe, elles demandent donc beaucoup plus dans l'espoir qu'elles n'auront jamais à se soucier d'en demander plus.
C'est ce que fait la machine virtuelle de Java: elle alloue un tas de mémoire au démarrage puis fonctionne à partir de cela. Par défaut, le noyau n'allouera la mémoire que lorsque votre application Java commencera à l'utiliser. Cependant, si vous désactivez la surcharge, le noyau prendra la réservation au sérieux. Elle ne permettra à l'allocation de réussir que si elle a réellement les ressources nécessaires.
Cependant, il y a un autre problème plus grave avec cette approche. Disons qu'une entreprise commence à demander une seule unité d'eau chaque jour (plutôt que par étapes de 10). Finalement, vous atteindrez un état où vous aurez 0 unités libres. Désormais, cette entreprise ne pourra plus allouer. C'est bien, qui se soucie de toute façon des grandes entreprises. Mais le problème est que les petites maisons ne pourront pas non plus demander plus d'eau! Vous ne pourrez pas construire de petites salles de bains publiques pour faire face à l'afflux soudain de touristes. Vous ne pourrez pas fournir d'eau d'urgence pour le feu dans la forêt voisine.
En termes informatiques: dans des situations de mémoire très faible sans surengagement, vous ne pourrez pas ouvrir un nouveau xterm, vous ne pourrez pas accéder à votre machine, vous ne pourrez pas ouvrir un nouvel onglet pour rechercher d'éventuelles corrections. En d'autres termes, la désactivation de la surcommission rend également votre bureau inutile lorsqu'il manque de mémoire.
3. Voici maintenant une façon intéressante de gérer le problème lorsqu'une entreprise commence à utiliser trop d'eau. La gestion de l'eau explose! Littéralement: il se rend sur le site du restaurant, y jette des dynamites et attend qu'il explose. Cela réduira instantanément de beaucoup les besoins en eau de la ville afin que de nouvelles personnes puissent emménager, vous pouvez créer des toilettes publiques, etc. Vous, en tant que maire, pouvez reconstruire le restaurant dans l'espoir que cette fois, il aura besoin de moins d'eau. Par exemple, vous direz aux gens de ne pas aller dans les restaurants s'il y a déjà trop de monde à l'intérieur (par exemple, vous ouvrirez moins d'onglets de navigateur).
C'est en fait ce que fait le noyau lorsqu'il manque de toutes les options et qu'il a besoin de mémoire: il appelle le tueur OOM. Il sélectionne une grande application (basée sur de nombreuses heuristiques) et la tue, libérant un tas de mémoire tout en conservant un bureau réactif. En fait, le noyau Android le fait de manière encore plus agressive: il tue l'application la moins récemment utilisée lorsque la mémoire est faible (par rapport au noyau de base qui ne le fait qu'en dernier recours). Cela s'appelle le Viking Killer dans Android.
Je pense que c'est l'une des solutions les plus simples au problème: ce n'est pas comme si vous aviez plus d'options que cela, alors pourquoi ne pas y remédier plus tôt que tard, non? Le problème est que le noyau fait parfois beaucoup de travail pour éviter d'invoquer le tueur OOM. C'est pourquoi vous voyez que votre bureau est très lent et que le noyau n'y fait rien. Mais heureusement, il existe une option pour invoquer le tueur OOM vous-même! Tout d'abord, assurez-vous que la clé magique sysrq est activée (par exemple echo 1 | sudo tee
/proc/sys/kernel/sysrq
) puis chaque fois que vous sentez que le noyau manque de mémoire, appuyez simplement sur Alt + SysRQ, Alt + f.
OK donc tout ça est sympa mais tu veux l'essayer? La situation de mémoire faible est très simple à reproduire. J'ai une application très simple pour ça. Vous devrez l'exécuter deux fois. La première exécution déterminera combien de RAM libre vous avez, la deuxième exécution créera la situation de mémoire faible. Notez que cette méthode suppose que vous avez désactivé l'échange (par exemple, faites un sudo swapoff -a
). Le code et l'utilisation suivent:
// gcc -std=c99 -Wall -Wextra -Werror -g -o eatmem eatmem.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int main(int argc, char** argv)
{
int limit = 123456789;
if (argc >= 2) {
limit = atoi(argv[1]);
}
setbuf(stdout, NULL);
for (int i = 1; i <= limit; i++) {
memset(malloc(1 << 20), 1, 1 << 20);
printf("\rAllocated %5d MiB.", i);
}
sleep(10000);
return 0;
}
Et voici comment vous l'utilisez:
$ gcc -std=c99 -Wall -Wextra -Werror -g -o eatmem eatmem.c
$ ./eatmem
Allocated 31118 MiB.Killed
$ ./eatmem 31110
Allocated 31110 MiB.Killed
La première invocation a détecté que nous disposions de 31 118 Mo de RAM libre. J'ai donc demandé à l'application d'allouer 31 110 Mo de RAM pour que le noyau ne le tue pas mais consomme presque toute ma mémoire. Mon système s'est figé: même le pointeur de la souris n'a pas bougé. J'ai appuyé sur Alt + SysRQ, Alt + f et cela a tué mon processus eatmem et le système a été restauré.
Même si nous avons couvert nos options ce que font dans une situation de faible mémoire, la meilleure approche (comme toute autre situation dangereuse) est de l'éviter en premier lieu. Il y a plusieurs façons de procéder. Une façon courante que j'ai vue est de mettre les applications qui se comportent mal (comme les navigateurs) dans des conteneurs différents de ceux du reste du système. Dans ce cas, le navigateur ne pourra pas affecter votre bureau. Mais la prévention elle-même est en dehors de la portée de la question, donc je n'écrirai pas à ce sujet.
TL; DR: Bien qu'il n'existe actuellement aucun moyen d'éviter complètement la pagination, vous pouvez atténuer l'arrêt complet du système en désactivant la surcharge. Mais votre système sera toujours inutilisable lors d'une situation de faible mémoire, mais d'une manière différente. Indépendamment de ce qui précède, dans une situation de faible mémoire, appuyez sur Alt + SysRQ, Alt + f pour tuer un grand processus du choix du noyau. Votre système devrait restaurer sa réactivité après quelques secondes. Cela suppose que la clé magique sysrq est activée (ce n'est pas le cas par défaut).