Hai bisogno di spiegazioni su Dimensione residente impostata / Dimensione virtuale


61

Ho scoperto che pidstatsarebbe un buon strumento per monitorare i processi. Voglio calcolare l'utilizzo medio di memoria di un particolare processo. Ecco alcuni esempi di output:

02:34:36 PM       PID  minflt/s  majflt/s     VSZ    RSS   %MEM  Command
02:34:37 PM      7276      2.00      0.00  349212 210176   7.14  scalpel

(Questo fa parte dell'output di pidstat -r -p 7276.)

Devo usare le informazioni Resident Set Size (RSS) o Virtual Size (VSZ) per calcolare il consumo medio di memoria? Ho letto alcune cose su Wikipedia e sui forum, ma non sono sicuro di comprendere appieno le differenze. Inoltre, sembra che nessuno di essi sia affidabile. Quindi, come posso monitorare un processo per ottenere il suo utilizzo della memoria?

Qualsiasi aiuto su questo argomento sarebbe utile.



Risposte:


63

RSS è la quantità di memoria che questo processo ha attualmente nella memoria principale (RAM). VSZ è la quantità di memoria virtuale che il processo ha in totale. Ciò include tutti i tipi di memoria, sia nella RAM che scambiati. Questi numeri possono essere distorti perché includono anche librerie condivise e altri tipi di memoria. Puoi avere cinquecento istanze di bashesecuzione e la dimensione totale del loro footprint di memoria non sarà la somma dei loro valori RSS o VSZ.

Se hai bisogno di avere un'idea più dettagliata dell'impronta di memoria di un processo, hai alcune opzioni. Puoi passare attraverso /proc/$PID/maped eliminare le cose che non ti piacciono. Se si tratta di librerie condivise, il calcolo potrebbe diventare complesso a seconda delle esigenze (che penso di ricordare).

Se ti interessa solo la dimensione dell'heap del processo, puoi sempre analizzare la [heap]voce nel mapfile. La dimensione allocata dal kernel per l'heap del processo può o meno riflettere il numero esatto di byte che il processo ha richiesto di allocare. Ci sono piccoli dettagli, interni del kernel e ottimizzazioni che possono farcela. In un mondo ideale, sarà tutto ciò di cui il tuo processo ha bisogno, arrotondato per eccesso al multiplo più vicino della dimensione della pagina del sistema ( getconf PAGESIZEti dirà di cosa si tratta - sui PC, probabilmente è 4.096 byte).

Se vuoi vedere quanta memoria ha allocato un processo , uno dei modi migliori è rinunciare alle metriche lato kernel. Invece, si strumentalizzano le funzioni di allocazione della memoria heap della libreria C con il LD_PRELOADmeccanismo. Personalmente, mi abuso leggermente valgrindper ottenere informazioni su questo genere di cose. (Notare che l'applicazione della strumentazione richiederà il riavvio del processo.)

Tieni presente che, poiché potresti anche eseguire il benchmarking dei tempi di esecuzione, ciò valgrindrenderà i tuoi programmi leggermente più lenti (ma probabilmente entro le tue tolleranze).


Molte grazie! Studierò le diverse opzioni. Sei stato più che utile! :)
Flanfl,

"Puoi avere cinquecento istanze di bash in esecuzione e la dimensione totale della loro impronta di memoria non sarà la somma dei loro valori RSS o VSZ." Ma la somma dei loro valori RSS sarà una buona approssimazione? Come la somma della colonna residente da statm, non ho bisogno di un valore esatto super affidabile, ma ho bisogno di sapere ad alto livello quanta memoria i miei processi java stanno usando
iloveretards,

3
Su Ubuntu è la /proc/$PID/mapsdifferenza di battitura o distro?
dolzenko,

1

Esempio eseguibile minimo

Perché ciò abbia un senso, è necessario comprendere le basi del paging: https://stackoverflow.com/questions/18431261/how-does-x86-paging-work e in particolare che il sistema operativo può allocare memoria virtuale tramite tabelle di pagine / la tenuta della sua memoria interna (memoria virtuale VSZ) prima che abbia effettivamente una memoria di supporto su RAM o disco (memoria residente RSS).

Ora per osservare questo in azione, creiamo un programma che:

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 a monte .

Compila ed esegui:

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

dove:

  • 0x1000000000 == 64GiB: 2x RAM fisica del mio computer di 32GiB
  • 0x200000000 == 8GiB: stampa la memoria ogni 8GiB, quindi dovremmo ottenere 4 stampe prima dell'incidente a circa 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: richiesto per Linux per consentirci di effettuare una chiamata mmap più grande della RAM fisica: https://stackoverflow.com/questions/2798330/ma maximum-memory-which-malloc-can-allocate/57687432#57687432

Uscita del programma:

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

Stato di uscita:

137

che secondo la regola 128 + numero di segnale significa che abbiamo ottenuto il numero di segnale 9, che man 7 signalè SIGKILL , che viene inviato dal killer di memoria insufficiente di Linux .

Interpretazione dell'output:

  • La memoria virtuale VSZ rimane costante su printf '0x%X\n' 0x40009A4 KiB ~= 64GiB(i psvalori sono in KiB) dopo la mmap.
  • RSS "utilizzo della memoria reale" aumenta pigramente solo quando tocchiamo le pagine. Per esempio:
    • alla prima stampa, abbiamo extra_memory_committed 0, il che significa che non abbiamo ancora toccato nessuna pagina. RSS è un piccolo 1648 KiBche è stato allocato per l'avvio normale del programma come area di testo, globi, ecc.
    • sulla seconda stampa, abbiamo scritto per 8388608 KiB == 8GiBvalore di pagine. Di conseguenza, RSS è aumentato di esattamente 8GIB a8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS continua ad aumentare con incrementi di 8GiB. L'ultima stampa mostra circa 24 GiB di memoria e prima che 32 GiB potessero essere stampati, il killer OOM ha ucciso il processo

Vedi anche: Hai bisogno di spiegazioni su Dimensione set residente / Dimensione virtuale

Registri killer OOM

I nostri dmesgcomandi hanno mostrato i registri killer OOM.

Un'interpretazione esatta di questi è stata chiesta a:

La prima riga del registro era:

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

Quindi vediamo che è stato interessante notare che è stato il demone MongoDB che gira sempre sul mio laptop in background a innescare il killer OOM, presumibilmente quando il povero cercava di allocare un po 'di memoria.

Tuttavia, il killer OOM non uccide necessariamente chi lo ha svegliato.

Dopo l'invocazione, il kernel stampa una tabella o processi tra cui 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

e più avanti vediamo che il nostro piccolo è stato main.outeffettivamente ucciso sulla precedente invocazione:

[ 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

Questo registro menziona il score 865processo che aveva, presumibilmente il punteggio più alto (peggiore) del killer OOM come menzionato in: Come fa il killer OOM a decidere quale processo uccidere per primo?

Inoltre, a quanto pare, tutto apparentemente è accaduto così in fretta che prima che la memoria liberata fosse spiegata, il processo è oomstato risvegliato di nuovo DeadlineMonitor:

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

e questa volta che ha ucciso qualche processo di Chromium, che di solito è il mio normale maiale di memoria del computer:

[ 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

Testato in Ubuntu 19.04, kernel Linux 5.0.0.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.