\newpage

Gestion de la mémoire
=====================

Linux a une gestion de la mémoire bien particulière[^vm-overcommit] : par
défaut, `malloc(3)` ne retournera jamais `NULL`. En se basant sur l'euristique
qu'un bloc mémoire demandé ne sera pas utilisé directement et que de nombreux
process ne feront pas un usage total des blocks qu'ils ont alloués, le noyau
permet d'allouer plus de mémoire qu'il n'y en a réellement disponible. La
mémoire est donc utilisée de manière plus efficace.

[^vm-overcommit]: Dépendant de la valeur de `/proc/sys/vm/overcommit_memory`,
    généralement 0. Voir
    <https://www.kernel.org/doc/Documentation/vm/overcommit-accounting>.

Mais évidemment, cela peut donner lieu à des situations où le noyau n'est plus
en mesure de trouver de bloc physiquement disponible, alors qu'ils avaient
effectivement été alloués au processus. Pour autant, ce n'est pas une raison
pour tuer ce processus, car il est peut-être vital pour le système (peut-être
est-ce `init` qui est en train de gérer le lancement d'un nouveau daemon). On
dit alors que le noyau est *Out-Of-Memory*.

Pour se sortir d'une telle situation, et après avoir tenté de vider les caches,
il lance son arme ultime, pour retrouver au plus vite de la mémoire :
l'*Out-Of-Memory killer*.


## OOM killer

Selon un algorithme dont on raconte qu'il ne serait pas basé entièrement sur
l'aléatoire[^oom-algo], un processus est tiré au sort (plus un processus occupe
de mémoire et plus il a de chance d'être tiré au sort) par l'OOM killer. Le
sort qui lui est réservé est tout simplement une mort brutale. Pour permettre
au système de disposer à nouveau de mémoire disponible. Si cela n'est pas
suffisant, un ou plusieurs autres processus peuvent être tués à tour de rôle,
jusqu'à ce que le système retrouve sa sérénité.

[^oom-algo]: ```c
/*
 * oom_badness - calculate a numeric value for how bad this task has been
 * @p: task struct of which task we should calculate
 * @p: current uptime in seconds
 *
 * The formula used is relatively simple and documented inline in the
 * function. The main rationale is that we want to select a good task
 * to kill when we run out of memory.
 *
 * Good in this context means that:
 * 1) we lose the minimum amount of work done
 * 2) we recover a large amount of memory
 * 3) we don't kill anything innocent of eating tons of memory
 * 4) we want to kill the minimum amount of processes (one)
 * 5) we try to kill the process the user expects us to kill, this
 *    algorithm has been meticulously tuned to meet the principle
 *    of least surprise ... (be careful when you change it)
 */```


## Esquiver l'OOM killer

Au sein d'un *cgroup* *memory*, le fichier `memory.oom_control` peut être
utilisé afin de recevoir une notification du noyau avant que l'OOM-killer
ne s'attaque à un processus de ce groupe.

Grâce à cette notification, il est possible de figer le processus pour
l'envoyer sur une autre machine. Et ainsi libérer la mémoire avant que l'OOM
killer ne passe.

Jetez un œil à [cet article parru LVM](https://lwn.net/Articles/590960/) à ce
sujet.
