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

331

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

tuban
la source
doublon possible de Comprendre les journaux de Linux oom-killer
msangel

Réponses:

499

RSS est la taille définie par le résident et est utilisé pour indiquer la quantité de mémoire allouée à ce processus et se trouvant dans la RAM. Il n'inclut pas la mémoire qui est permutée. 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 pile et de 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 permutée, la mémoire allouée mais non utilisée et la mémoire provenant 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 sont réellement en mémoire (le reste est permuté ou inutilisé), et il n'a réellement chargé que 1000K des bibliothèques partagées et 400K de son propre binaire puis:

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 RSS, vous pouvez facilement vous retrouver avec plus d'espace que votre système.

La mémoire allouée peut également ne pas être en RSS tant qu'elle n'est pas réellement utilisée par le programme. Donc, si votre programme a alloué un tas de mémoire à l'avance, puis l'utilise au fil du temps, vous pourriez voir RSS augmenter et VSZ rester le même.

Il existe également PSS (taille de jeu proportionnelle). Il s'agit d'une mesure plus récente qui suit la mémoire partagée en tant que proportion utilisée par le processus en cours. Donc, s'il y avait deux processus utilisant la même bibliothèque partagée d'avant:

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

Les threads partagent tous le même espace d'adressage, de sorte que le RSS, VSZ et PSS pour chaque thread est identique à tous les autres threads du processus. Utilisez ps ou top pour afficher ces informations sous linux / unix.

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

Regarde aussi:

jmh
la source
17
Je crois que RSS ne comprend la mémoire des bibliothèques liées dynamiquement. Si 3 processus sont utilisés libxml2.so, la bibliothèque partagée sera comptée dans chacun de leurs flux RSS, donc la somme de leurs flux RSS sera supérieure à la mémoire réelle utilisée.
nfm
1
C'est exact. J'ai fixé ma réponse, merci pour les avertissements.
jmh
Je suis sur ubuntu 16.04, et il y a un processus Java avec 1.2G RES et 4.5G VIRT à partir de la topcommande. Ce système n'a pas d'échange, swapon --showne renvoie rien. Comment peux-tu expliquer ça? Si vsz est swap + bibliothèques partagées, dans ce cas, les bibliothèques partagées sont supérieures à 3,3 G? C'est possible? Juste vraiment confus ...
Aaron Wang
Je ne suis pas vraiment sûr. Jetez un œil à cette réponse sur l'utilisation de la mémoire virtuelle Java: stackoverflow.com/a/561450/622115 . Version courte: VSZ peut inclure un espace de tas alloué et non utilisé ainsi que des fichiers mappés en mémoire.
jmh
Génial. Ajoutez simplement quelque chose. si vous malloc (100 Ko), alors n'utilisez que 1 Ko en fait. Le rss est 1K et vsz est 100K, même s'il n'y a pas d'échange ici.
keniee van
53

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 en a pas nécessairement mémoire réelle derrière tout cela en ce moment).

Notez que de nos jours des machines virtuelles courantes, la mémoire physique du point de vue de la machine peut ne pas être vraiment de la mémoire physique réelle.

caf
la source
Voulez-vous fournir plus d'informations que ce que l'abréviation signifie?
Pithikos
10

Exemple exécutable minimal

Pour que cela ait un sens, vous devez comprendre les bases de la pagination: comment fonctionne la pagination x86? et en particulier que l'OS peut allouer de la mémoire virtuelle via des tables de pages / sa tenue de livre de mémoire interne (mémoire virtuelle VSZ) avant d'avoir réellement un stockage de sauvegarde sur RAM ou 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 garantir que chacune de ces pages passe de la mémoire 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 dans: Utilisation de la mémoire du processus en cours en C

principal 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;

/* /programming/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:
         * /programming/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 .

Compiler et exécuter:

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 == 64 Go: 2x RAM physique de mon ordinateur de 32 Go
  • 0x200000000 == 8GiB: imprimez 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: requis pour 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

ce qui, selon la règle du numéro de signal 128 +, signifie que nous avons le numéro de signal 9, qui man 7 signalest SIGKILL , qui est envoyé par le tueur à mémoire insuffisante de Linux .

Interprétation de sortie:

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

Voir également: /unix/35129/need-explanation-on-resident-set-size-virtual-size

Journaux de tueur OOM

Nos dmesgcommandes ont montré les journaux du tueur 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 voyons donc que ce qui est intéressant, c'est que le démon MongoDB qui s'exécute toujours dans mon ordinateur portable en arrière-plan a d'abord déclenché le tueur OOM, probablement lorsque le pauvre essayait d'allouer de la mémoire.

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

Après l'invocation, le noyau imprime une table ou des processus comprenant 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.outa é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 865processus qui a obtenu, probablement le score de tueur OOM le plus élevé (le pire), comme indiqué sur: /unix/153585/how-does-the-oom-killer-decide-which- processus pour tuer en premier

Autre fait intéressant, tout s'est apparemment passé si vite qu'avant que la mémoire libérée ne soit prise en compte, oomle DeadlineMonitorprocessus a été réveillé à nouveau :

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

et cette fois qui a tué un processus de chrome, qui est généralement le porc de mémoire normal 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.

Ciro Santilli 郝海东 冠状 病 六四 事件 法轮功
la source
8

Je pense que beaucoup a déjà été dit à propos de RSS vs VSZ. Du point de vue administrateur / programmeur / utilisateur, lorsque je conçois / code des applications, je suis plus préoccupé par la RSZ, (mémoire résidente), et lorsque vous tirez de plus en plus de variables (en tas), vous verrez cette valeur augmenter. Essayez un programme simple pour créer une allocation d'espace basée sur malloc en boucle, et assurez-vous de remplir les données dans cet espace malloc'd. RSS continue de progresser. En ce qui concerne VSZ, il s'agit davantage de mappage de mémoire virtuelle que Linux, et l'une de ses principales fonctionnalités dérivées des concepts de systèmes d'exploitation conventionnels. La gestion VSZ est effectuée par la gestion de la mémoire virtuelle du noyau, pour plus d'informations sur VSZ, voir la description de Robert Love sur mm_struct et vm_struct, qui font partie de la structure de base des données task_struct dans le noyau.

Anugraha Sinha
la source
Faites-vous référence au livre "Linux Kernel Development" de Love?
benjimin
1

Ils ne sont pas gérés, mais mesurés et éventuellement limités (voir getrlimitappel système, également sur getrlimit (2) ).

RSS signifie la taille de l'ensemble résident (la partie de votre espace d'adressage virtuel assis dans la RAM).

Vous pouvez interroger l' espace d'adressage virtuel du processus 1234 à l'aide de proc (5) avec cat /proc/1234/mapset son état (y compris la consommation de mémoire) à traverscat /proc/1234/status

Basile Starynkevitch
la source
1
Bien que ce lien puisse répondre à la question, il est préférable d'inclure les parties essentielles de la réponse ici et de fournir le lien de référence. Les réponses de lien uniquement peuvent devenir invalides si la page liée change. - De l'avis
Maak
J'ai fourni un deuxième lien. L'un d'eux restera valide
Basile Starynkevitch