Linux commencera-t-il à tuer mes processus sans me demander si la mémoire devient insuffisante?


66

J'exécutais un script shell avec des commandes permettant d'exécuter plusieurs programmes gourmands en mémoire (2 à 5 Go) dos à dos. Lorsque je suis retourné vérifier l'état d'avancement de mon script, j'ai été surpris de découvrir que certains de mes processus étaient Killedconformes aux instructions de mon terminal. Plusieurs programmes avaient déjà été successivement terminés avant les programmes qui ont été Killedlancés plus tard , mais tous les programmes ont ensuite échoué dans une erreur de segmentation (qui peut ou non être due à un bogue dans mon code, continuez à lire).

J'ai examiné l'historique d'utilisation du cluster que j'utilisais et constaté qu'une personne avait commencé à exécuter plusieurs processus gourmands en mémoire en même temps, épuisant ainsi la mémoire réelle (et peut-être même l'espace de permutation) disponible pour le cluster. Autant que je sache, ces processus gourmands en mémoire ont commencé à fonctionner à peu près au même moment où j'ai commencé à avoir des problèmes avec mes programmes.

Est-il possible que Linux ait tué mes programmes une fois qu'il a commencé à manquer de mémoire? Et est-il possible que les erreurs de segmentation que j’ai eues plus tard soient dues au manque de mémoire disponible pour exécuter mes programmes (au lieu d’un bogue dans mon code)?


2
Lorsque vous allouez de la mémoire, avez-vous une déclaration pour vérifier si la mémoire a été allouée avec succès? Cela devrait permettre de déterminer s’il ya un bogue dans votre code ou s’il s’agit d’un manque de mémoire dans le système.
unxnut

Réponses:


72

Ça peut.

Il existe deux conditions de mémoire insuffisantes que vous pouvez rencontrer sous Linux. Ce que vous rencontrez dépend de la valeur de sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Introduction:
Le noyau peut effectuer ce que l’on appelle «mémoire surchargée». C'est à ce moment que le noyau alloue aux programmes plus de mémoire que ce qui est réellement présent dans le système. Ceci est fait dans l'espoir que les programmes n'utiliseront pas réellement toute la mémoire allouée, car il s'agit d'un événement assez courant.

surcommit_memory = 2

Lorsque overcommit_memoryest défini sur 2, le noyau n'effectue aucune surcharge. À la place, lorsqu'un programme se voit allouer de la mémoire, l'accès à cette mémoire est garanti. Si le système ne dispose pas de suffisamment de mémoire disponible pour satisfaire une demande d'allocation, le noyau renverra simplement un échec pour la demande. Il appartient au programme de gérer la situation avec élégance. S'il ne vérifie pas que l'allocation a réussi quand elle a réellement échoué, l'application rencontrera souvent un segfault.

Dans le cas du segfault, vous devriez trouver une ligne comme celle-ci dans la sortie de dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

Les at 0moyens que l'application a tenté d'accéder un pointeur non initialisé, ce qui peut être le résultat d'un appel d'allocation de mémoire a échoué (mais pas la seule).

surcommit_memory = 0 et 1

Lorsque l'option overcommit_memoryest définie sur 0ou 1, la surconsommation est activée et les programmes sont autorisés à allouer plus de mémoire que ce qui est réellement disponible.

Cependant, lorsqu'un programme souhaite utiliser la mémoire qui lui a été allouée, mais que le noyau s'aperçoit qu'il ne dispose pas de suffisamment de mémoire pour la satisfaire, il doit récupérer de la mémoire. Il essaie d’abord d’effectuer diverses tâches de nettoyage de la mémoire, telles que le vidage des caches, mais si cela ne suffit pas, il met fin au processus. Cette terminaison est effectuée par le MOO-Killer. OOM-Killer examine le système pour voir quels programmes utilisent quelle mémoire, depuis combien de temps ils fonctionnent, qui les utilise et un certain nombre d'autres facteurs permettant de déterminer celui qui sera tué.

Une fois le processus supprimé, la mémoire qu'il utilisait est libérée et le programme qui vient de provoquer la condition de mémoire insuffisante dispose désormais de la mémoire dont il a besoin.

Toutefois, même dans ce mode, les demandes d’allocation peuvent toujours être refusées aux programmes. Le cas overcommit_memoryéchéant 0, le noyau essaie de deviner quand il devrait commencer à refuser les demandes d'allocation. Lorsqu'il est défini sur 1, je ne sais pas quelle détermination il utilise pour déterminer quand il doit refuser une demande, mais il peut refuser les demandes très volumineuses.

Vous pouvez voir si OOM-Killer est impliqué en examinant le résultat dmesget en recherchant des messages tels que:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB

Donc, il semble que les deux situations me sont arrivées.
NeutronStar

@ Josué Je viens de mettre à jour la réponse. J'ai oublié de mentionner que vous pouvez toujours avoir des échecs d'allocation quand il overcommit_memoryest mis à 0 ou 2.
Patrick

Je pense qu’il serait utile d’ éditer un lien vers Taming the Killer Killer .
0xC0000022L

@ 0xC0000022L Merci, c'est un bon article (bien qu'un peu obsolète). Je ne voulais rien dire sur le contrôle du tueur OOM, car cela ne fait pas partie de la question (et ce n'est pas un sujet bref), et nous avons une tonne d'autres questions à ce sujet.
Patrick

1
@mikeserv Je ne dis pas que le comportement du tueur de MOO n'a rien à voir avec le contrôler. La question était de savoir si Linux tuerait ses programmes. Pour empêcher linux de le faire en premier lieu, il faut établir qu’il s’agit bien de le faire. Et si overcommit_memory=2le tueur de MOO n'est même pas activé, le contrôler est donc inutile. Cependant, une fois que nous établissons qu'il s'agit du tueur OOM, cela devient un autre sujet qui est couvert par de nombreuses autres questions et réponses ici.
Patrick

16

La vérité est que, quelle que soit la manière dont vous le regardez, que votre processus soit étranglé par le gestionnaire de mémoire du système ou par quelque chose d'autre, il s'agit toujours d' un bogue. Qu'est-il arrivé à toutes ces données que vous venez de traiter en mémoire? Cela aurait dû être sauvegardé.

Bien overcommit_memory=qu’il s’agisse du moyen le plus courant de configurer la gestion de MOO Linux, il est également possible de l’ajuster par processus, par exemple:

echo [-+][n] >/proc/$pid/oom_adj

L'utilisation -17de ce qui précède exclura un processus de la gestion de mémoire insuffisante. Ce n’est probablement pas une bonne idée en général, mais si vous êtes à la recherche de bogues, il pourrait en valoir la peine, surtout si vous souhaitez savoir s’il s’agissait de MOO ou de votre code. L'incrémentation positive du nombre rendra le processus plus susceptible d'être tué lors d'un événement de MOO, ce qui pourrait vous permettre de renforcer la résilience de votre code dans les situations de mémoire insuffisante et de vous assurer de sortir correctement, le cas échéant.

Vous pouvez vérifier les paramètres actuels du gestionnaire de MOO par processus, comme suit:

cat /proc/$pid/oom_score 

Sinon, vous pourriez devenir suicidaire:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Cela configurera l'ordinateur pour qu'il redémarre en cas d'insuffisance de mémoire. Vous définissez ce qui Xprécède sur le nombre de secondes pendant lesquelles vous souhaitez que l'ordinateur s'arrête après une panique du noyau avant de redémarrer. Devenir fou.

Et si, pour une raison quelconque, vous décidez que vous l’aimez, rendez-le persistant:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf

C'est un cluster partagé que j'utilise, je suis sûr que les autres utilisateurs n'apprécieraient pas qu'il redémarre sans leur consentement.
NeutronStar

3
@ Joshua - je doute très sérieusement que quiconque l'aimerait - cela défie même les lois de la robotique d'Asimov. D'autre part, comme je l'ai mentionné, vous pouvez également configurer le MOO par processus. Ce qui signifie que vous pouvez trier personnellement en fonction de vos propres ensembles de règles définis par processus. Ce genre de chose semble être particulièrement utile dans un scénario de cluster partagé.
mikeserv
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.