Linux commencera-t-il à tuer mes process sans me requestr si la memory devient trop courte?

J'exécutais un script shell avec des commands pour exécuter plusieurs programmes gourmands en memory (2-5 Go) dos à dos. Quand je suis revenu vérifier la progression de mon script, j'ai été surpris de découvrir que certains de mes process ont été Killed , comme mon terminal me l'a rapporté. Plusieurs programmes s'étaient déjà succédé avant que les programmes qui avaient été Killed suite n'aient commencé, mais tous les programmes ont ensuite échoué dans une erreur de segmentation (qui peut être ou non due à un bug dans mon code).

J'ai regardé l'historique d'utilisation du cluster particulier que j'utilisais et j'ai vu que quelqu'un commençait à exécuter plusieurs process gourmands en memory en même time, ce qui épuisait la memory réelle (et peut-être même l'espace de swap) disponible pour le cluster. Autant que je peux comprendre, ces process intensifs en memory 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 a tué mes programmes une fois qu'il a commencé à manquer de memory? Et est-il possible que les défauts de segmentation que j'ai eu plus tard étaient dus au manque de memory disponible pour exécuter mes programmes (au lieu d'un bogue dans mon code)?

Ça peut.

Il y a 2 différentes conditions de memory que vous pouvez rencontrer dans Linux. Ce que vous rencontrez dépend de la valeur de sysctl vm.overcommit_memory ( /proc/sys/vm/overcommit_memory )

Introduction:
Le kernel peut effectuer ce que l'on appelle la memory overcommit. C'est à ce moment que le kernel alloue plus de memory qu'il n'y en a réellement dans le système. Ceci est fait dans l'espoir que les programmes n'utiliseront pas toute la memory qu'ils allouent, car c'est un phénomène assez courant.

overcommit_memory = 2

Lorsque overcommit_memory est défini sur 2 , le kernel n'effectue aucun overcommit du tout. Au lieu de cela, lorsqu'un programme est alloué à la memory, il est garanti l'access à cette memory. Si le système n'a pas assez de memory libre pour satisfaire une request d'allocation, le kernel returnnera simplement un échec pour la requête. C'est au programme de gérer avec élégance la situation. S'il ne vérifie pas que l'allocation a réussi lorsqu'il a réellement échoué, l'application rencontre souvent un segfault.

Dans le cas du segfault, vous devriez find 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] 

La valeur at 0 indique que l'application a tenté d'accéder à un pointeur non initialisé, ce qui peut résulter d'un appel d'allocation de memory échoué (mais ce n'est pas le seul moyen).

overcommit_memory = 0 et 1

Lorsque overcommit_memory est défini sur 0 ou 1 , overcommit est activé et les programmes sont autorisés à allouer plus de memory que ce qui est réellement disponible.

Cependant, lorsqu'un programme veut utiliser la memory, il a été alloué, mais le kernel trouve qu'il n'a pas assez de memory pour le satisfaire, il a besoin de récupérer de la memory.
Il tente d'abord d'effectuer diverses tâches de nettoyage de la memory, telles que le vidage des caches, mais si cela ne suffit pas, il mettra fin à un process. Cette résiliation est effectuée par le OOM-Killer. Le KOM-Killer regarde le système pour voir quels programmes utilisent quelle memory, combien de time ils ont couru, qui les exécute, et un certain nombre d'autres facteurs pour déterminer lequel est tué.

Une fois le process détruit, la memory utilisée est libérée et le programme qui vient de provoquer l'état de memory insuffisante possède la memory dont il a besoin.

Cependant, même dans ce mode, les requests d'allocation peuvent toujours être refusées aux programmes. Lorsque overcommit_memory est à 0 , le kernel essaie de deviner quand il devrait commencer à refuser les requests d'allocation. Lorsqu'il est défini sur 1 , je ne suis pas sûr de la détermination qu'il utilise pour déterminer quand il doit refuser une requête, mais il peut refuser des requêtes très volumineuses.

Vous pouvez voir si le KOM-Killer est impliqué en regardant la sortie de demsg et en trouvant 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 

La vérité est que, peu importe la façon dont vous regardez – si votre process s'est étouffé en raison du gestionnaire de memory du système ou en raison de quelque chose d'autre – c'est toujours un bug. Qu'est-il arrivé à toutes ces données que vous étiez en train de traiter en memory? Cela aurait dû être sauvegardé.

Alors que overcommit_memory= est le moyen le plus général de configurer la gestion des OOM Linux, il est également réglable par process comme:

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

L'utilisation de -17 dans ce qui précède exclut un process de la memory management insuffisante. Probablement pas une bonne idée en général, mais si vous faites de la chasse aux bugs, cela pourrait en valoir la peine – surtout si vous voulez savoir si c'est votre MOO ou votre code. L'incrémentation positive du nombre rendra le process plus susceptible d'être tué dans un événement de MOO, ce qui pourrait vous permettre de renforcer la résilience de votre code dans les situations de faible memory et de vous assurer de sortir avec élégance si nécessaire.

Vous pouvez vérifier les parameters actuels du gestionnaire de MOO par process, comme:

 cat /proc/$pid/oom_score 

Sinon, vous pourriez aller suicidaire:

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

Cela mettra l'ordinateur à redémarrer en cas de condition de memory insuffisante. Vous définissez le X ci-dessus sur le nombre de secondes que vous souhaitez arrêter l'ordinateur après une panique du kernel 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