Mémoire

Un article de Haypo.

Retour à la page précédente Retour aux articles de programmation

Notes sur l'utilisation de la mémoire dans un programme.

Sommaire

[modifier] État actuel

[modifier] Savoir lire l'état de la mémoire

Lorsqu'on fait un top, on a des fois des sueurs froides en interprétant mal les différentes colonnes.

$ top
...
(je tape M pour trier par utilisation de la mémoire)
...
  PID USER      PR  NI  VIRT  RES  SHR S %CPU %MEM    TIME+  COMMAND
15404 haypo     15   0 73240  40m  22m S  0.3  8.2   0:35.20 konqueror
22370 root      15   0  359m  22m 2800 S  0.0  4.6   9:12.06 Xorg
12098 haypo     15   0 89944  19m 7740 S  0.0  3.8   0:18.36 gajim.py
14355 haypo     15   0 40836  11m 7388 S  0.0  2.3   0:30.56 gvim

Colonnes concernant la mémoire :

  • VIRT : Taille de la mémoire virtuelle. Notion assez lointaine de l'utilisation mémoire. En gros, c'est la taille totale que pourrait atteindre un programme s'il utilisait toute la mémoire. Or cette valeur est très loin de l'utilisation réelle.
  • RES : Mémoire « résidente ». C'est cette valeur qu'il faut lire en premier quand on veut savoir quel programme utilise toute la mémoire. C'est la mémoire qu'un programme utilise réelle et juste pour son usage personnel.
  • SHR : Mémoire « partagée ». C'est la mémoire utilisée partagées avec les autres processus.

« RSS. Taille de l’ensemble résident : nombre de pages dont le processus dispose en mémoire réelle, moins 3 pour des raisons administratives. Il s’agit juste des pages contenant les espaces de code, donnée et pile. Ceci n’inclut ni les pages en attente de chargement ni celles qui ont été swappées. »

[modifier] getrusage()

La fonction getrusage() renseigne l'utilisation des ressources du processus courant. Champs renseignant sur l'état de la mémoire :

  • ru_maxrss : Taille résidente maximale
  • ru_ixrss : Taille de mémoire partagée
  • ru_idrss : Taille des données non partagées
  • ru_isrss : Taille de pile
  • ru_minflt : Demandes de pages
  • ru_majflt : Nombre de fautes de pages
  • ru_nswap : Nombre de swaps

Les valeurs sont exprimées en nombre de pages. Il faut lire la taille d'une page pour avoir la valeur en octets.

[modifier] free

Commande free :

$ free
             total       used       free     shared    buffers     cached
Mem:        506488     356632     149856          0      18892     155056
-/+ buffers/cache:     182684     323804
Swap:      1485972     163940    1322032

[modifier] /proc/self/statm

$ cat /proc/self/statm
689 144 121 4 0 61 0

Signification des colonnes :

  1. Taille totale du programme (en pages)
  2. Taille résidente du programme (en pages)
  3. Nombre de pages partagées
  4. Nombre de pages de code
  5. Nombre de pages de bibliothèques
  6. Nombre de pages de donnée ou de pile
  7. Nombre de pages touchées (dirty pages)

Source : (en) Red Hat Enterprise Linux 3: Reference Guide (Chapter 5. The proc File System).

[modifier] /proc/meminfo

État de la mémoire physique. Lignes intéressantes :

$ cat /proc/meminfo
MemTotal:       506488 kB
MemFree:         82396 kB
Buffers:         36448 kB
Cached:         173540 kB
SwapTotal:     1485972 kB
SwapFree:      1324976 kB

[modifier] /proc/self/status

Le fichier /proc/self/status contient des lignes intéressantes :

$ grep Vm /proc/self/status 
VmPeak:     2828 kB
VmSize:     2828 kB
VmLck:         0 kB
VmHWM:       744 kB
VmRSS:       744 kB
VmData:      156 kB
VmStk:        84 kB
VmExe:        92 kB
VmLib:      1304 kB
VmPTE:        12 kB

Les différentes lignes :

* VmPeak : Valeur maximale de la mémoire virtuelle depuis la naissance du processus
* VmSize : Taille de la mémoire virtuelle
* VmLck : ???
* VmHWM : ???
* VmRSS : Mémoire « résidente »
* VmData : Taille de la mémoire (des données) en lecture seule
* VmStk : Taille de la pile
* VmExe : Taille du code
* VmLib : Mémoire des bibliothèques partagées
* VmPTE : ???

[modifier] ELC

Matt Mackall prépare des patchs pour le noyau Linux permettant d'avoir une meilleure idée de la mémoire utilisée par une application : http://lwn.net/Articles/230975/

[modifier] Mémoire et Xorg

Il faut utiliser le programme xrestop pour lire la répartition en mémoire des pixmaps par processus.

Lisez aussi X.org myths de Stéphane Marchesin.

[modifier] Pile

Sous Linux, la taille a une taille d'environ 8 Mo.

On peut changer la taille de la pile initiale lors de la compilation, via la commande : « ld --stack=... ».

Pour détecter le dépassement de la pile (« notifiée » par un signal SIGSEGV envoyé par le noyau), on peut utiliser le programme : stack.c.

On peut utiliser une pile dédié aux gestionnaires de signal avec signaltstack().

On peut limiter la taille de la pile d'un thread avec pthread_attr_setstacksize().

gcc a plusiers options relatives à la gestion de la pile:

  • « -fstack-check »
  • « -mmax-stack-frame=n » : Avertissement si une fonction utilise plus de n octets de pile <= ne fonctionne que pour l'architecture CRIS
  • « -fstack-limit-register=reg »
  • «-fstack-limit-symbol=sym »
  • « -fno-stack-limit » : Pas de limlite de pile
  • (dans le code) « __attribute__ ((sp_switch ("alt_stack"))) » indique qu'on utilise la pile de la variable alt_stack (void *alt_stack = malloc(...))

La fonction alloca() alloue de la mémoire sur la pile : en fait, c'est simplement un changement de valeur d'ESP (sur i386). gcc a la fonction __builtin_alloca(). La fonction alloca() a un comportement indéfini lorsque la limite de la mémoire est dépassée, il ne faut donc pas l'utiliser. Voir :

[modifier] Python

Surveiller l'utilisation de la mémoire : Heapy et (plus vieux et n'est plus maintenu) pysizer.

[modifier] pymalloc

Le gestionnaire de mémoire internet de Python 2.3 et 2.4, pymalloc, est bogué. Il ne libère jamais la mémoire : lisez le billet d'Evan Jones pour en savoir plus. Evan Jones a justement corrigé ce bug et son travail a été intégré dans Python 2.5 : lisez l'annonce d'Evan Jones et l'annonce de Tim Peters sur la liste de diffusion python-dev. Tim Peters a repris le travail d'Evan Jones, l'a corrigé et l'a commité dans le trunk de Python.

[modifier] setrlimit

Sous Linux, seul setrlimit(RLIMIT_AS) fonctionne. setrlimit(RLIMIT_RSS) et setrlimit(RLIMIT_DATA) ne fonctionnent pas. Lire un email d'Alan Cox à ce sujet.