466 votes

Qu'est-ce que RSS et VSZ dans la gestion de la mémoire Linux

Quels sont les RSS et les VSZ dans la gestion de la mémoire Linux? Dans un environnement multithreadé, comment peuvent-ils être gérés et suivis?

691voto

jmh Points 1760

RSS est la Resident Set Size et est utilisée pour montrer combien de mémoire est allouée à ce processus et est en RAM. Il n'inclut pas la mémoire qui est mise en swap. Il inclut la mémoire des bibliothèques partagées tant que les pages de ces bibliothèques sont réellement en mémoire. Il inclut toute la mémoire de la pile et du tas.

VSZ est la Taille de la mémoire virtuelle. Il inclut toute la mémoire à laquelle le processus peut accéder, y compris la mémoire qui est mise en swap, la mémoire qui est allouée, mais non utilisée, et la mémoire qui provient de bibliothèques partagées.

Donc, si le processus A a un binaire de 500K et est lié à 2500K de bibliothèques partagées, a 200K d'allocations de pile/tas dont 100K est réellement en mémoire (le reste est mis en swap ou inutilisé), et il a réellement chargé seulement 1000K des bibliothèques partagées et 400K de son propre binaire alors :

RSS: 400K + 1000K + 100K = 1500K
VSZ: 500K + 2500K + 200K = 3200K

Comme une partie de la mémoire est partagée, de nombreux processus peuvent l'utiliser, donc si vous additionnez toutes les valeurs de RSS, vous pouvez facilement obtenir plus d'espace que ce que votre système possède.

La mémoire qui est allouée peut également ne pas être dans RSS tant qu'elle n'est pas réellement utilisée par le programme. Donc si votre programme alloue une quantité de mémoire au départ, puis l'utilise au fil du temps, vous pourriez voir RSS augmenter et VSZ rester le même.

Il y a aussi PSS (proportional set size). C'est une mesure plus récente qui suit la mémoire partagée comme une proportion utilisée par le processus en cours. Donc, s'il y avait deux processus utilisant la même bibliothèque partagée de tout à l'heure :

PSS: 400K + (1000K/2) + 100K = 400K + 500K + 100K = 1000K

Les threads partagent tous le même espace d'adressage, donc le RSS, le VSZ et le PSS pour chaque thread sont identiques à tous les autres threads dans le processus. Utilisez ps ou top pour visualiser ces informations dans linux/unix.

Il y a bien plus que cela, pour en savoir plus consultez les références suivantes:

Voir également :

31 votes

Je crois que RSS comprend la mémoire des bibliothèques liées dynamiquement. S'il y a 3 processus utilisant libxml2.so, la bibliothèque partagée sera comptée dans chacun de leurs RSS, donc la somme de leurs RSS sera plus importante que la mémoire réellement utilisée.

4 votes

C'est exact. J'ai corrigé ma réponse, merci pour l'information.

0 votes

Je suis sur ubuntu 16.04, et il y a un processus java avec 1,2G RES et 4,5G VIRT affiché par la commande top. Ce système n'a pas de swap, swapon --show ne renvoie rien. Comment expliquez-vous cela? Si vsz représente swap + bibliothèques partagées, dans ce cas, les bibliothèques partagées dépassent-elles 3,3G? Est-ce possible? Vraiment confus...

60voto

caf Points 114951

RSS est Resident Set Size (mémoire résidente physique - cela occupe actuellement de l'espace dans la mémoire physique de la machine), et VSZ est Virtual Memory Size (espace d'adressage alloué - cela a des adresses allouées dans la carte mémoire du processus, mais il n'y a pas nécessairement de mémoire réelle derrière tout cela en ce moment).

Notez qu'à l'époque actuelle des machines virtuelles courantes, la mémoire physique du point de vue de la machine pourrait ne pas être vraiment de la mémoire physique réelle.

1 votes

Peux-tu fournir plus d'informations que le sens de l'abréviation?

41voto

Ciro Santilli Points 3341

Exemple minimal exécutable

Pour que cela ait un sens, vous devez comprendre les bases de la pagination : Comment fonctionne la pagination sur x86 ? et, en particulier, que le système d'exploitation peut allouer de la mémoire virtuelle via des tables de pages / sa comptabilité interne (mémoire virtuelle VSZ) avant de disposer d'un support de stockage en RAM ou sur disque (mémoire résidente RSS).

Maintenant pour observer cela en action, créons un programme qui :

  • alloue plus de RAM que notre mémoire physique avec mmap
  • écrit un octet sur chaque page pour s'assurer que chacune de ces pages passe de la mémoire uniquement virtuelle (VSZ) à la mémoire réellement utilisée (RSS)
  • vérifie l'utilisation de la mémoire du processus avec l'une des méthodes mentionnées ci-dessus : Utilisation de la mémoire du processus actuel en C

main.c

#define _GNU_SOURCE
#include <assert.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/mman.h>
#include <unistd.h>

typedef struct {
    unsigned long size,resident,share,text,lib,data,dt;
} ProcStatm;

/* https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c/7212248#7212248 */
void ProcStat_init(ProcStatm *result) {
    const char* statm_path = "/proc/self/statm";
    FILE *f = fopen(statm_path, "r");
    if(!f) {
        perror(statm_path);
        abort();
    }
    if(7 != fscanf(
        f,
        "%lu %lu %lu %lu %lu %lu %lu",
        &(result->size),
        &(result->resident),
        &(result->share),
        &(result->text),
        &(result->lib),
        &(result->data),
        &(result->dt)
    )) {
        perror(statm_path);
        abort();
    }
    fclose(f);
}

int main(int argc, char **argv) {
    ProcStatm proc_statm;
    char *base, *p;
    char system_cmd[1024];
    long page_size;
    size_t i, nbytes, print_interval, bytes_since_last_print;
    int snprintf_return;

    /* Decide how many ints to allocate. */
    if (argc < 2) {
        nbytes = 0x10000;
    } else {
        nbytes = strtoull(argv[1], NULL, 0);
    }
    if (argc < 3) {
        print_interval = 0x1000;
    } else {
        print_interval = strtoull(argv[2], NULL, 0);
    }
    page_size = sysconf(_SC_PAGESIZE);

    /* Allocate the memory. */
    base = mmap(
        NULL,
        nbytes,
        PROT_READ | PROT_WRITE,
        MAP_SHARED | MAP_ANONYMOUS,
        -1,
        0
    );
    if (base == MAP_FAILED) {
        perror("mmap");
        exit(EXIT_FAILURE);
    }

    /* Write to all the allocated pages. */
    i = 0;
    p = base;
    bytes_since_last_print = 0;
    /* Produce the ps command that lists only our VSZ and RSS. */
    snprintf_return = snprintf(
        system_cmd,
        sizeof(system_cmd),
        "ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == \"%ju\") print}'",
        (uintmax_t)getpid()
    );
    assert(snprintf_return >= 0);
    assert((size_t)snprintf_return < sizeof(system_cmd));
    bytes_since_last_print = print_interval;
    do {
        /* Modify a byte in the page. */
        *p = i;
        p += page_size;
        bytes_since_last_print += page_size;
        /* Print process memory usage every print_interval bytes.
         * We count memory using a few techniques from:
         * https://stackoverflow.com/questions/1558402/memory-usage-of-current-process-in-c */
        if (bytes_since_last_print > print_interval) {
            bytes_since_last_print -= print_interval;
            printf("extra_memory_committed %lu KiB\n", (i * page_size) / 1024);
            ProcStat_init(&proc_statm);
            /* Check /proc/self/statm */
            printf(
                "/proc/self/statm size resident %lu %lu KiB\n",
                (proc_statm.size * page_size) / 1024,
                (proc_statm.resident * page_size) / 1024
            );
            /* Check ps. */
            puts(system_cmd);
            system(system_cmd);
            puts("");
        }
        i++;
    } while (p < base + nbytes);

    /* Cleanup. */
    munmap(base, nbytes);
    return EXIT_SUCCESS;
}

GitHub en amont .

Compilez et exécutez :

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o main.out main.c
echo 1 | sudo tee /proc/sys/vm/overcommit_memory
sudo dmesg -c
./main.out 0x1000000000 0x200000000
echo $?
sudo dmesg

où :

  • 0x1000000000 == 64GiB : 2x la RAM physique de mon ordinateur de 32GiB
  • 0x200000000 == 8GiB : imprimer la mémoire tous les 8GiB, donc nous devrions obtenir 4 impressions avant le crash à environ 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory : nécessaire à Linux pour nous permettre de faire un appel mmap plus grand que la RAM physique : Mémoire maximale que malloc peut allouer

Sortie du programme :

extra_memory_committed 0 KiB
/proc/self/statm size resident 67111332 768 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 1648

extra_memory_committed 8388608 KiB
/proc/self/statm size resident 67111332 8390244 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 8390256

extra_memory_committed 16777216 KiB
/proc/self/statm size resident 67111332 16778852 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 16778864

extra_memory_committed 25165824 KiB
/proc/self/statm size resident 67111332 25167460 KiB
ps -o pid,vsz,rss | awk '{if (NR == 1 || $1 == "29827") print}'
  PID    VSZ   RSS
29827 67111332 25167472

Killed

Statut de sortie :

137

qui par le 128 + règle du nombre de signaux signifie que nous avons le numéro du signal 9 qui man 7 signal dit est SIGKILL qui est envoyé par le Linux tueur hors-mémoire .

Interprétation de la sortie :

  • La mémoire virtuelle VSZ reste constante à printf '0x%X\n' 0x40009A4 KiB ~= 64GiB ( ps sont en KiB) après le mmap.
  • L'utilisation réelle de la mémoire du RSS n'augmente paresseusement que lorsque nous touchons les pages. Par exemple :
    • sur la première impression, nous avons extra_memory_committed 0 ce qui signifie que nous n'avons encore touché aucune page. Le RSS est un petit 1648 KiB qui a été alloué pour le démarrage normal du programme comme la zone de texte, les globales, etc.
    • sur la deuxième impression, nous avons écrit à 8388608 KiB == 8GiB de pages. Par conséquent, le RSS a augmenté d'exactement 8GIB pour atteindre 8390256 KiB == 8388608 KiB + 1648 KiB
    • Le RSS continue d'augmenter par incréments de 8GiB. La dernière impression montre environ 24 GiB de mémoire, et avant que 32 GiB puissent être imprimés, le tueur OOM a tué le processus

Voir aussi : https://unix.stackexchange.com/questions/35129/need-explanation-on-resident-set-size-virtual-size

Les journaux des tueurs de l'OOM

Notre site dmesg Les commandes ont montré les journaux des tueurs d'OOM.

Une interprétation exacte de ceux-ci a été demandée :

La toute première ligne du journal était :

[ 7283.479087] mongod invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

Nous constatons donc qu'il est intéressant de noter que c'est le démon MongoDB qui tourne toujours en arrière-plan dans mon ordinateur portable qui a déclenché le premier OOM killer, probablement lorsque la pauvre chose essayait d'allouer de la mémoire.

Cependant, le tueur du MOM ne tue pas nécessairement celui qui l'a réveillé.

Après l'invocation, le noyau imprime une table ou des processus incluant le nom de l'utilisateur. oom_score :

[ 7283.479292] [  pid  ]   uid  tgid total_vm      rss pgtables_bytes swapents oom_score_adj name
[ 7283.479303] [    496]     0   496    16126        6   172032      484             0 systemd-journal
[ 7283.479306] [    505]     0   505     1309        0    45056       52             0 blkmapd
[ 7283.479309] [    513]     0   513    19757        0    57344       55             0 lvmetad
[ 7283.479312] [    516]     0   516     4681        1    61440      444         -1000 systemd-udevd

et plus loin, nous voyons que notre propre petit main.out a en fait été tué lors de l'invocation précédente :

[ 7283.479871] Out of memory: Kill process 15665 (main.out) score 865 or sacrifice child
[ 7283.479879] Killed process 15665 (main.out) total-vm:67111332kB, anon-rss:92kB, file-rss:4kB, shmem-rss:30080832kB
[ 7283.479951] oom_reaper: reaped process 15665 (main.out), now anon-rss:0kB, file-rss:0kB, shmem-rss:30080832kB

Ce journal mentionne le score 865 que ce processus avait, vraisemblablement le plus haut (pire) score de tueur d'OOM comme mentionné à : https://unix.stackexchange.com/questions/153585/how-does-the-oom-killer-decide-which-process-to-kill-first

Il est également intéressant de noter que tout s'est apparemment passé si vite qu'avant que la mémoire libérée ne soit prise en compte, le fichier oom a été réveillé à nouveau par le DeadlineMonitor processus :

[ 7283.481043] DeadlineMonitor invoked oom-killer: gfp_mask=0x6200ca(GFP_HIGHUSER_MOVABLE), order=0, oom_score_adj=0

et cette fois, cela a tué un processus Chromium, qui est habituellement le plus gros consommateur de mémoire de mon ordinateur :

[ 7283.481773] Out of memory: Kill process 11786 (chromium-browse) score 306 or sacrifice child
[ 7283.481833] Killed process 11786 (chromium-browse) total-vm:1813576kB, anon-rss:208804kB, file-rss:0kB, shmem-rss:8380kB
[ 7283.497847] oom_reaper: reaped process 11786 (chromium-browse), now anon-rss:0kB, file-rss:0kB, shmem-rss:8044kB

Testé dans Ubuntu 19.04, noyau Linux 5.0.0.

Documentation sur le noyau Linux

https://github.com/torvalds/linux/blob/v5.17/Documentation/filesystems/proc.rst a quelques points. Le terme "VSZ" n'y est pas utilisé mais "RSS" l'est, et il n'y a rien de très éclairant (surprise ? !).

Au lieu de VSZ, le noyau semble utiliser le terme VmSize qui apparaît, par exemple, sur /proc/$PID/status .

Quelques citations d'intérêt :

La première de ces lignes montre les mêmes informations que celles qui sont affichées pour le mappage dans /proc/PID/maps. Les lignes suivantes indiquent la taille du mappage (size) ; la taille de chaque page allouée lors de la sauvegarde d'un VMA (KernelPageSize), qui est généralement la même que la taille des entrées de la table des pages ; la taille de la page utilisée par la MMU lors de la sauvegarde d'un VMA (dans la plupart des cas, la même que KernelPageSize) ; la quantité de mappage qui réside actuellement en RAM (RSS) ; la part proportionnelle du processus de ce mappage (PSS) ; et le nombre de pages partagées et privées propres et sales dans le mappage.

La "taille d'ensemble proportionnelle" (PSS) d'un processus est le nombre de pages qu'il possède en mémoire, où chaque page est divisée par le nombre de processus qui la partagent. Ainsi, si un processus a 1000 pages pour lui tout seul et 1000 pages partagées avec un autre processus, son PSS sera de 1500.

Notez que même une page qui fait partie d'un mappage MAP_SHARED, mais qui n'a qu'un seul pte mappé, c'est-à-dire qui est actuellement utilisée par un seul processus, est comptabilisée comme privée et non comme partagée.

On peut donc deviner quelques autres choses :

  • les bibliothèques partagées utilisées par un seul processus apparaissent dans le RSS, si plus d'un processus les possède alors pas
  • PSS a été mentionné par jmh et a une approche plus proportionnelle entre "je suis le seul processus qui détient la bibliothèque partagée" et "il y a N processus qui détiennent la bibliothèque partagée, donc chacun détient la mémoire/N en moyenne".

13voto

premraj Points 120

VSZ - Taille de l'ensemble virtuel

  • La taille de l'ensemble virtuel est une taille de mémoire attribuée à un processus (programme) lors de son exécution initiale. La mémoire de la taille de l'ensemble virtuel est simplement un nombre indiquant la quantité de mémoire disponible pour l'exécution d'un processus.

RSS - Taille de l'ensemble résident (sorte de RAM)

  • Contrairement à VSZ (Taille de l'ensemble virtuel), RSS est la mémoire actuellement utilisée par un processus. Il s'agit d'un nombre réel en kilooctets indiquant la quantité de RAM utilisée par le processus en cours.

Source

0 votes

Lorsque la valeur est extraite du fichier stat, elle pourrait être par exemple 8674, cela représente-t-il alors 8674 kBytes ? Le manuel Linux ne mentionne que le RSS est égal au "nombre de pages" que le processus détient en mémoire. Que veulent-ils dire par là ? Une page est-elle équivalente à un kilo-octet ? /proc/[pid]/stat ``` man7.org/linux/man-pages/man5/proc.5.html ``` (24) rss %ld ```

7voto

Anugraha Sinha Points 101

Je pense que beaucoup de choses ont déjà été dites à propos de RSS vs VSZ. Du point de vue d'un administrateur/programmeur/utilisateur, lorsque je conçois/code des applications, je me préoccupe davantage du RSZ (mémoire résidente), car à chaque fois que vous ajoutez de plus en plus de variables (allouées dynamiquement), vous verrez cette valeur augmenter. Essayez de créer un programme simple pour allouer de l'espace en boucle basé sur malloc, et assurez-vous de remplir les données dans cet espace malloc'd. Le RSS ne cesse d'augmenter. En ce qui concerne le VSZ, il s'agit plus d'une mappage de mémoire virtuelle que fait Linux, et l'une de ses fonctionnalités de base issue des concepts des systèmes d'exploitation conventionnels. La gestion du VSZ est effectuée par la gestion de la mémoire virtuelle du noyau, pour plus d'informations sur le VSZ, consultez la description de Robert Love sur mm_struct et vm_struct, qui font partie de la structure de données de tâche de base dans le noyau.

1 votes

Faites-vous référence au livre "Linux Kernel Development" de Love?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X