Solution 1 :
Réglage overcommit_ratio
à 80 n'est probablement pas la bonne action. Définir une valeur inférieure à 100 est presque toujours incorrect.
La raison en est que les applications Linux allouent plus que ce dont elles ont réellement besoin. Supposons qu'ils allouent 8 Ko pour stocker une chaîne de caractères de texte. Eh bien, c'est plusieurs Ko inutilisés ici. Les applications le font souvent, et c'est pour cela que l'overcommit est conçu.
Donc, fondamentalement, avec un overcommit à 100, le noyau ne permettra pas aux applications d'allouer plus de mémoire que vous n'en avez (swap + ram). Le régler à moins de 100 signifie que vous n'utiliserez jamais toute votre mémoire. Si vous souhaitez définir ce paramètre, vous devez le définir sur une valeur supérieure à 100 en raison du scénario mentionné ci-dessus, qui est assez courant.
Maintenant, en ce qui concerne votre problème avec le déclenchement du tueur OOM, la définition manuelle de la surengagement ne résoudra probablement pas ce problème. Le paramètre par défaut (détermination heuristique) est assez intelligent.
Si vous souhaitez voir si c'est vraiment la cause du problème, regardez /proc/meminfo
lorsque le tueur OOM s'exécute. Si vous voyez que Committed_AS
est proche de CommitLimit
, mais free
affiche toujours de la mémoire libre disponible, alors oui, vous pouvez ajuster manuellement le surengagement pour votre scénario. Si vous définissez cette valeur trop bas, le tueur de MOO commencera à tuer des applications alors que vous avez encore beaucoup de mémoire libre. Une valeur trop élevée peut entraîner la mort d'applications aléatoires lorsqu'elles essaient d'utiliser la mémoire qui leur a été allouée, mais qui n'est pas réellement disponible (lorsque toute la mémoire est réellement utilisée).
Solution 2 :
La section 9.6 "Overcommit and OOM" dans la doc mentionnée par @dunxd est particulièrement explicite sur les dangers d'autoriser le surengagement. Cependant, le 80
m'a semblé intéressant aussi, alors j'ai fait quelques tests.
Ce que j'ai trouvé, c'est que le overcommit_ratio
affecte la RAM totale disponible pour TOUS les processus. Les processus racine ne semblent pas être traités différemment des processus utilisateur normaux.
Réglage du ratio sur 100
ou moins devrait fournir la sémantique classique où les valeurs de retour de malloc/sbrk
sont fiables. Définir des ratios inférieurs à 100
pourrait être un moyen de réserver plus de RAM pour des activités non liées aux processus comme la mise en cache, etc.
Donc, sur mon ordinateur avec 24 Go de RAM, avec swap désactivé, 9 Go en cours d'utilisation, avec top
montrant
Mem: 24683652k total, 9207532k used, 15476120k free, 19668k buffers
Swap: 0k total, 0k used, 0k free, 241804k cached
Voici quelques overcommit_ratio
les paramètres et la quantité de RAM que mon programme consommateur de ram pourrait récupérer (en touchant chaque page) - dans chaque cas, le programme s'est terminé proprement une fois malloc
échoué.
50 ~680 MiB
60 ~2900 MiB
70 ~5200 MiB
100 ~12000 MiB
En exécuter plusieurs à la fois, même avec certains en tant qu'utilisateur root, n'a pas changé la quantité totale qu'ils ont consommée ensemble. Il est intéressant de noter qu'il n'a pas pu consommer les 3 derniers Gio ou plus ; le free
n'a pas beaucoup baissé en dessous de ce qui est montré ici :
Mem: 24683652k total, 20968212k used, 3715440k free, 20828k buffers
Les expériences étaient désordonnées - tout ce qui utilise malloc au moment où toute la RAM est utilisée a tendance à planter, car de nombreux programmeurs sont terribles pour vérifier les échecs de malloc en C, certaines bibliothèques de collection populaires l'ignorent complètement, et C++ et divers autres langages sont même pire.
La plupart des premières implémentations de RAM imaginaires que j'ai vues devaient gérer un cas très spécifique, où un seul grand processus - disons 51% + de la mémoire disponible - avait besoin de fork()
afin de exec()
un programme de soutien, généralement beaucoup, beaucoup plus petit. Les systèmes d'exploitation avec une sémantique de copie sur écriture autoriseraient le fork()
, mais à condition que si le processus forké essayait réellement de modifier trop de pages mémoire (chacune d'entre elles devant alors être instanciée comme une nouvelle page indépendante du processus énorme initial), il finirait par être tué. Le processus parent n'était en danger que s'il allouait plus de mémoire et pouvait gérer l'épuisement, dans certains cas simplement en attendant un peu qu'un autre processus meure, puis en continuant. Le processus enfant se remplace généralement par un programme (généralement plus petit) via exec()
et était alors libre de la condition.
Le concept de surengagement de Linux est une approche extrême permettant à la fois le fork()
se produire ainsi que de permettre à des processus uniques de se surallouer massivement. Les décès causés par OOM-killer se produisent de manière asynchrone, même pour les programmes qui le font gérer l'allocation de mémoire de manière responsable. Personnellement, je déteste l'ensemble du système overcommit en général et le oom-killer en particulier - il favorise une approche diabolique de la gestion de la mémoire qui infecte les bibliothèques et, à travers elles, toutes les applications qui les utilisent.
Je suggérerais de définir le ratio sur 100 et d'avoir également une partition d'échange qui ne finirait généralement par être utilisée que par d'énormes processus - qui n'utilisent souvent qu'une infime partie de la partie d'eux-mêmes qui est insérée dans l'échange, et donc protéger la grande majorité des processus de la mauvaise fonctionnalité OOM killer. Cela devrait protéger votre serveur Web d'une mort aléatoire, et s'il a été écrit pour gérer malloc
de manière responsable, même à l'abri de se suicider (mais ne pariez pas sur ce dernier).
Cela signifie que je l'utilise dans /etc/sysctl.d/10-no-overcommit.conf
vm.overcommit_memory = 2
vm.overcommit_ratio = 100