La gestion de la mémoire sous Linux

From Deimos.fr / Bloc Notes Informatique
Jump to: navigation, search
Linux

Software version Kernel 2.6.32+
Operating System Red Hat 6.3
Debian 7
Website Kernel Website
Last Update 06/05/2013
Others

1 Les pages

Lorsque l'on regarde dans /proc/meminfo, les pages 'Inactive Clean' correspondent aux pages libres. Si le kernel doit allouer des pages à un process, il peut prendre ces pages depuis la liste de pages libres ou l'inactive clean. Les pages étant utilisées par les process sont référencées comme étant des pages actives. Dans le cas de mémoire partagée, une page peut avoir plusieurs process qui la référencent.

  • Aussi longtemps que la page aura au moins un process qui la référencera, elle restera dans la liste active.
  • A partir du moment ou tous les process ont relâchés leur référence à la page, elle devient inactive. Si une page active a été modifiée par le process qui a été référencé, elle deviendra une page inactive dirty. Les dirty pages contiennent des données qui peuvent être écrites sur le disque.
  • Si la page n'a pas été modifiée depuis la dernière lecture sur disque, elle sera une page inactive clean. Elle est alors disponible pour une allocation.
  • Les pages libres sont les pages qui n'ont pas encore été allouées à un process

Pour trouver la mémoire dirty et clean :

Command awk
awk 'BEGIN {}
/Shared_Clean/{ CLEAN += $2; }
/Shared_Dirty/{ DIRTY += $2; }
END {
print "Shared_Clean: " CLEAN;
print "Shared_Dirty: " DIRTY;
}' /proc/1/smaps

2 La réclamation des dirty pages

La mémoire n'étant pas illimité, le kernel ne peut garder les dirty pages en RAM éternellement. Les pages qui sont dirty mais qui ne sont plus utilisées, sont vidées sur le disque. C'est le thread kernel pdflush qui gère cette tâche, il y a d'ailleurs 2 thread minimum pour gérer cette opération. L'utilisation du cache mémoire créer un fort besoin de control sur la façon dont les pages sont réclamées. Pour voir le nombre de thread pdflush actuellement présents :

Command sysctl
> sysctl vm.nr_pdflush_threads
vm.nr_pdflush_threads = 0

Lorsque l'on vide les dirty pages sur le disque, le but est d'éviter les burst IO pour ne pas saturer le disque. Le démond pdflush écrit les données sur le disque de manière constante et douce. Par défaut les 2 threads pdflush vont faire leurs actions mais d'autres peuvent se lancer (jusqu'à 8), si les 2 saturent afin d'assurer des écritures parallèles sur plusieurs disques. Si le ratio du nombre de pages qui sont dirty par rapport au nombre de pages RAM disponibles atteint un certain pourcentage, les process vont se bloquer pendant que le pdflush écrira les données de façon synchrone. Il existe plusieurs options pour améliorer le pdflush :

Configuration File /etc/sysctl.conf
# Pourcentage (totale de mémoire) de dirty pages a partir duquel le pdflush doit commencer à écrire
vm.dirty_background_ratio=<value>
# Pourcentage (totale de mémoire) de dirty pages a partir duquel le process lui même doit commencer à écrire les données dirty
vm.dirty_ratio=<value>
# Intervalle entre lequel le pdflush va se réveiller (100ths/sec) (Temps d'observation). Mettez 0 pour désactiver
vm.dirty_writeback_centisecs=<value>
# Définit quand les données sont assez vieilles (100ths/sec) pour être interceptées par pdflush (temps d'attente).
vm.dirty_expire_centisecs=<value>

Si lors d'un ps, il est possible de voir kswap et pdflush. Si ces 2 éléments sont en état D (iowait), c'est probablement causé par le kernel.

Pour commiter toutes les dirty pages et buffers :

Command
sync
echo s > /proc/sysrq-trigger

3 La réclamation des clean pages

Il existe plusieurs façons de vider les caches. Pour écrire toutes les clean pages présentent dans le page cache sur le disque :

Command echo
echo 1 > /proc/sys/vm/drop_caches

Warning WARNING
Attention toutefois à ne pas faire ça pendant les heures de production due aux IO provoquées

Il est également possible de flusher les dentries et les indoes :

Command echo
echo 2 > /proc/sys/vm/drop_caches

Pour flusher la totalité des cleans pages, dentries et inodes:

Command
echo 3 > /proc/sys/vm/drop_caches

4 OOM

OOM (Out Of Memory) peut arriver. Il existe pour cela un processus appellé l'oomkiller. Lorsqu'il n'y a plus de swap, plus de RAM, il va tuer des processus. Il se déclenchera si :

  • Vous n'avez plus d'espace en mémoire (incluant la RAM)
  • Il n'y a plus de pages disponibles dans la ZONE_NORMAL ou ZONE_HIGHMEM[1]
  • Il n'y a plus de mémoire disponible dans la table des mapping de pages

Il est également possible de rajouter de la swap à chaud[2] pour éviter un plantage dû à un OOM.

Pour voir le niveau l'immunité de l'OOM-Kill sur un processus, il faut regarder le score des process (ici PID 1) :

Command cat
> cat /proc/1/oom_score
0

Pour demander manuellement à l'oom-kill de se lancer :

Command echo
echo f > /proc/sysrq-trigger

Cependant, il ne tuera pas de process s'il y a suffisamment d’espace mémoire. Vous pouvez regarder dans les logs (messages ou syslog) afin de voir le résultat de celui ci.

Il est possible de protéger des démons de l'oom-kill de cette façon :

Command echo
echo n > /proc/<PID>/oom_adj

  • n : correspond au score qui sera multiplié par 2
Notes Notes
Il faut savoir que l'oom_adj est déprécié sur les kernel récent. Il faut utiliser /proc/<PID>/oom_score_adj à la place

Warning WARNING
Ce n'est pas parce que vous réglez le le score OOM d'un processus que ses fils en hériteront ! Faites attention à cela !

Enfin, il est possible de désactiver l'oom-kill :

Configuration File /etc/sysctl.conf
vm.panic_on_oom=1

Une petite dédicace pour les développeurs en herbe : ceci n'est pas une solution pour régler les fuites mémoire !

5 Détecter les fuites mémoires

Il existe 2 types de fuites mémoire :

  • Les virtuelles : lorsqu'un process fait des requêtes qui ne sont pas dans l’espace virtuelle d'adresses (vsize)
  • Les réelles : lorsqu'un process n'arrive pas à libérer la mémoire (RSS)
  • On utilise sar pour voir les échanges côté système :
Command sar
sar -R 1 120

  • On utilise la commande ps combinée avec watch :
Command watch
watch -n 1 'ps axo pid,comm,rss,vsize | grep sshd'

  • Utiliser Valgrind pour les programmes en C :
Command valgrind
valgrind --tool=memcheck cat /prox/$$/maps

Afin de comprendre un peu mieux ce qui se passe avec ps ou top :

  • VIRT stands for the virtual size of a process, which is the sum of memory it is actually using, memory it has mapped into itself (for instance the video card's RAM for the X server), files on disk that have been mapped into it (most notably shared libraries), and memory shared with other processes. VIRT represents how much memory the program is able to access at the present moment.
  • RES stands for the resident size, which is an accurate representation of how much actual physical memory a process is consuming. (This also corresponds directly to the %MEM column) This will virtually always be less than the VIRT size, since most programs depend on the C or other library.
  • SHR indicates how much of the VIRT size is actually sharable memory or libraries. In the case of libraries, it does not necessarily mean that the entire library is resident. For example, if a program only uses a few functions in a library, the whole library is mapped and will be counted in VIRT and SHR, but only the parts of the library file containing the functions being used will actually be loaded in and be counted under RES.

6 La swap

Il est parfois nécessaire de supprimer toutes les pages ou segments d'un processus de la mémoire centrale. Dans ce cas le processus sera dit swappé, et toutes les données lui appartenant seront stockées en mémoire de masse. Cela peut survenir pour des processus dormant depuis longtemps, alors que le système d'exploitation a besoin d'allouer de la mémoire aux processus actifs. Les pages ou segments de code (programme) ne seront jamais swappés, mais tout simplement réassignés, car on peut les retrouver dans le fichier correspondant au programme (le fichier de l'exécutable). Pour cette raison, le système d'exploitation interdit l'accès en écriture à un fichier exécutable en cours d'utilisation ; symétriquement, il est impossible de lancer l'exécution d'un fichier tant qu'il est tenu ouvert pour un accès en écriture par un autre processus.[3]

Il est important d'allouer suffisamment de swap à vos systèmes, même si vous avez largement assez de mémoire RAM. Si vous avez plusieurs disques, n'hésitez pas à créer plusieurs partitions et à leur mettre une priorité égale au niveau du montage dans fstab :

Configuration File /etc/fstab
[...]
/dev/mapper/vg0-swap none            swap    sw,pri=3              0       0
/dev/mapper/vg1-swap none            swap    sw,pri=3              0       0
/dev/mapper/vg2-swap none            swap    sw,pri=3              0       0
[...]

Grâce à cela, le démon kswapd ferra du round robin, tout comme un RAID 0 ferrait afin d'augmenter les performances.

Comment savoir quelle taille de swap allouer à un système ? C'est une question assez complexe qui a déjà fait beaucoup de débat. Voici une formule qui fonctionne plutôt pas mal :

RAM SWAP
Entre 1 et 2 GB 1,5 x la taille de la RAM
Entre 2 et 8 GB égale à la taille de la RAM
Plus de 8 GB 0,75 x la taille de la RAM

La recherche de pages inactive peut prendre du CPU. Sur des systèmes disposant de beaucoup de RAM, rechercher et démapper des pages inactives consomment plus de disque et CPU que d'écrire des pages anonymes sur le disque. Il est donc possible de paramétrer la façon dont le kernel va swapper. Ceci allant de 0 à 100. Plus on monte la valeur du swappiness, plus on force le système à swapper, ce qui réduit les I/O comme le montre le tableau ci dessous[4] :

vm.swappiness value Total I/O Average Swap
0 273.57 MB/s 0 MB
20 273.75 MB/s 0 MB
40 273.52 MB/s 0 MB
60 229.01 MB/s 23068 MB
80 195.63 MB/s 25587 MB
100 184.30 MB/s 26006 MB

Voilà comment modifier la swapiness :

Configuration File /etc/sysctl.conf
vm.swappiness=60

Il faut savoir que le kernel aime swaper les pages anonymes lorsque le % de la mémoire mappée dans les tables de pages + vm.swappiness >= 100

Il existe également d'autres paramètres intéressant pour réduire le temps d'attente :

Configuration File /etc/sysctl.conf
# Nombre de pages que le kernel va lire pour une page fault. Ca aide à réduire les mouvements de tête de lecture de disque. Par défaut c'est 2 puissance page-cluster
vm.page-cluster=<value>
# Permet de controller pour combien de temps un process est protégé de la pagination lorsqu'il y a un vidage mémoire (en secondes)
vm.swap_token_timeout=<seconds>

S'il ne reste que peu de mémoire, le kernel va commencer par tuer les processus en espace utilisateur en commençant par ceux qui font la plus mauvaise utilisation de la mémoire (accès mémoire par rapport à l'allocation que les processus en font).

7 References

  1. ^ L'adressage mémoire et son allocation#UMA
  2. ^ SWAP : Création de swap dynamique
  3. ^ http://fr.wikipedia.org/wiki/M%C3%A9moire_virtuelle#Swapping
  4. ^ http://www.linuxvox.com/2009/10/what-is-the-linux-kernel-parameter-vm-swappiness/

Memory management and tuning options in Red Hat Enterprise Linux