Le log du problème
Pour commencer, on va passer en revue les informations disponibles dans le fichier /var/log/syslog/kernel.log
(j'ai déjà enlevé les parties inintéressantes):
Free pages: 14732kB (1536kB HighMem) Active:219399 inactive:14723 dirty:0 writeback:0 unstable:0 free:3683 slab:3741 mapped:214946 pagetables:871 DMA free:12516kB min:16kB low:32kB high:48kB active:0kB inactive:0kB present:16384kB pages_scanned:331 all_unreclaimable? yes protections[]: 0 0 0 Normal free:680kB min:928kB low:1856kB high:2784kB active:236kB inactive:148kB present:901120kB pages_scanned:544 all_unreclaimable? yes protections[]: 0 0 0 HighMem free:1536kB min:512kB low:1024kB high:1536kB active:877360kB inactive:58744kB present:1179648kB pages_scanned:0 all_unreclaimable? no protections[]: 0 0 0 DMA: 5*4kB 4*8kB 3*16kB 2*32kB 3*64kB 1*128kB 1*256kB 1*512kB 1*1024kB 1*2048kB 2*4096kB = 12516kB Normal: 0*4kB 1*8kB 2*16kB 0*32kB 0*64kB 1*128kB 0*256kB 1*512kB 0*1024kB 0*2048kB 0*4096kB = 680kB HighMem: 0*4kB 2*8kB 3*16kB 0*32kB 1*64kB 3*128kB 2*256kB 1*512kB 0*1024kB 0*2048kB 0*4096kB = 1536kB Swap cache: add 228354, delete 228254, find 68953/77275, race 0+4 0 bounce buffer pages Free swap: 2062584kB 524288 pages of RAM 294896 pages of HIGHMEM 5620 reserved pages 12977 pages shared 100 pages swap cached Out of Memory: Killed process 24620 (java).
Comme ça, ça fait peur.
Et ce qui est surtout bizarre, c'est qu'il semble qu'il y a encore de la mémoire ! Ce qui est confirmé par la mention :
HighMem free:1536kB
et surtout :
Free swap: 2062584kB
Effectivement, de la mémoire haute et plein de mémoire virtuelle, même si non-performante, sont disponibles. Mais alors, pourquoi l'OOM Killer se met-il en route ?
La mémoire sous Linux
C'est assez compliqué, je vais essayer de simplifier. J'espère que les puristes me pardonneront et/ou me corrigeront le cas échéant.
Pour des raisons que je n'expliquerai pas ici, mais que vous pourrez lire en consultant les liens marqués plus bas, dans tout système en 32 bits qui contient plus de 1 Go de mémoire, la mémoire physique est divisée en deux parties : la partie basse (LOWMEM
) et la partie haute (HIGHMEM
). On peut voir leurs états avec la commande free
:
[root@localhost ~]# free -lm total used free shared buffers cached Mem: 2026 1106 919 0 12 92 Low: 874 218 655 High: 1151 887 264 -/+ buffers/cache: 1001 1024 Swap: 2015 377 1638
Voici les points-clés concernant ces zones :
- Certains travaux ne peuvent être effectués dans la partie haute
- Le noyau a besoin de la partie basse pour adresser la partie haute
- L'OOM Killer se met en route s'il n'y a plus de mémoire disponible dans l'une de ces parties
Retour au problème
C'est bien ce dernier point qu'on voit dans le syslog :
Normal free:680kB min:928kB low:1856kB high:2784kB active:236kB inactive:148kB present:901120kB pages_scanned:544 all_unreclaimable? yes
La mémoire disponible (680ko) est inférieure à la valeur minimum configurée (928ko) !
Une solution
La solution que j'ai mise en oeuvre a été de demander gentiment au noyau de garder de la zone basse de mémoire, de manière plus agressive. Cela se fait par exemple avec la commande suivante :
# echo "250" > /proc/sys/vm/lower_zone_protection
Ou en mettant la ligne suivante dans /etc/sysctl.conf
:
vm.lower_zone_protection = 250
Évidemment une meilleure solution aurait été de passer à un noyau récent. On fait pas toujours ce qu'on veut.
Documentation
- HighMem sur Linux-mm
- Virtual Memory: the problem sur LWN
- High Memory In The Linux Kernel sur Kerneltrap
- Un e-mail détaillé sur le problème et ses solutions