Co to są RSS i VSZ w zarządzaniu pamięcią w systemie Linux

331

Co to są RSS i VSZ w zarządzaniu pamięcią w systemie Linux? Jak w środowisku wielowątkowym można zarządzać i śledzić oba te elementy?

tuban
źródło
możliwy duplikat Zrozumienia dzienników zabójcy Linuksa
msangel

Odpowiedzi:

499

RSS to Resident Set Size i służy do pokazania, ile pamięci jest przydzielone do tego procesu i czy znajduje się w pamięci RAM. Nie obejmuje wymienionej pamięci. Obejmuje pamięć z bibliotek współdzielonych, o ile strony z tych bibliotek znajdują się w pamięci. Obejmuje całą pamięć stosu i sterty.

VSZ to rozmiar pamięci wirtualnej. Obejmuje całą pamięć, do której proces może uzyskać dostęp, w tym pamięć wymienną, pamięć przydzieloną, ale nieużywaną oraz pamięć pochodzącą z bibliotek współdzielonych.

Więc jeśli proces A ma 500 KB pliku binarnego i jest połączony z 2500 KB bibliotek współużytkowanych, ma 200 000 przydziałów stosu / sterty, z których 100 000 faktycznie znajduje się w pamięci (reszta jest zamieniona lub nieużywana) i faktycznie załadował tylko 1000 KB bibliotek współdzielonych i 400 KB własnego pliku binarnego następnie:

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

Ponieważ część pamięci jest współdzielona, ​​wiele procesów może z niej korzystać, więc jeśli dodasz wszystkie wartości RSS, możesz z łatwością uzyskać więcej miejsca niż system.

Przydzielona pamięć może również nie znajdować się w RSS, dopóki nie zostanie faktycznie wykorzystana przez program. Więc jeśli twój program przydzielił sporo pamięci z góry, a następnie zużywa ją z czasem, możesz zobaczyć, jak RSS się podnosi, a VSZ pozostaje taki sam.

Istnieje również PSS (proporcjonalny rozmiar zestawu). Jest to nowsza miara, która śledzi pamięć współdzieloną jako część wykorzystywaną przez bieżący proces. Więc jeśli dwa procesy korzystały z tej samej biblioteki współużytkowanej wcześniej:

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

Wszystkie wątki mają tę samą przestrzeń adresową, więc RSS, VSZ i PSS dla każdego wątku są identyczne z wszystkimi innymi wątkami w tym procesie. Użyj ps lub top, aby wyświetlić te informacje w systemie Linux / UNIX.

Jest o wiele więcej niż to, aby dowiedzieć się więcej, sprawdź następujące referencje:

Zobacz także:

jmh
źródło
17
Wierzę RSS robi zawierać pamięć z dynamicznie połączonych bibliotek. Jeśli używane są 3 procesy libxml2.so, biblioteka współdzielona będzie zliczana w każdym z ich kanałów RSS, więc suma ich kanałów RSS będzie większa niż faktyczna używana pamięć.
nfm
1
To jest poprawne. Naprawiłem swoją odpowiedź, dziękuję za podniesienie głowy.
jmh
Jestem na Ubuntu 16.04, a proces Java ma 1.2G RES i 4.5G VIRT pokazany z toppolecenia. Ten system nie ma żadnej wymiany, swapon --shownic nie zwraca. Jak to wytłumaczysz? Jeśli vsz to swap + biblioteki współdzielone, w takim przypadku biblioteki współdzielone są większe niż 3.3G? Czy to możliwe? Po prostu bardzo zdezorientowany ...
Aaron Wang
Nie jestem do końca pewny. Spójrz na tę odpowiedź na temat wykorzystania pamięci wirtualnej Java: stackoverflow.com/a/561450/622115 . Wersja skrócona: VSZ może zawierać przydzielone i niewykorzystane miejsce sterty, a także pliki mapowane w pamięci.
jmh
Świetny. Po prostu dodaj coś. jeśli robisz malloc (100 KB), wtedy faktycznie używaj tylko 1 KB. Rss to 1K, a vsz to 100K, nawet jeśli nie ma tutaj wymiany.
keniee van 25'18
53

RSS to Resident Set Size (fizycznie rezydentna pamięć - obecnie zajmuje miejsce w pamięci fizycznej maszyny), a VSZ to Virtual Memory Size (przydzielona przestrzeń adresowa - ma adresy przydzielone na mapie pamięci procesu, ale niekoniecznie rzeczywista pamięć za tym wszystkim teraz).

Należy pamiętać, że w dzisiejszych czasach zwykłych maszyn wirtualnych pamięć fizyczna z punktu widzenia maszyny może nie być tak naprawdę rzeczywistą pamięcią fizyczną.

caf
źródło
Chcesz podać więcej informacji niż to, co oznacza skrót?
Pithikos,
10

Minimalny możliwy do uruchomienia przykład

Aby to miało sens, musisz zrozumieć podstawy stronicowania: Jak działa stronicowanie x86? aw szczególności, że system operacyjny może przydzielić pamięć wirtualną za pomocą tablic stron / przechowywania wewnętrznej pamięci (pamięć wirtualna VSZ), zanim faktycznie będzie miała pamięć zapasową na RAM lub dysku (pamięć rezydentna RSS).

Teraz, aby to zaobserwować w akcji, stwórzmy program, który:

  • przydziela więcej pamięci RAM niż nasza pamięć fizyczna mmap
  • zapisuje jeden bajt na każdej stronie, aby upewnić się, że każda z tych stron przechodzi z pamięci tylko wirtualnej (VSZ) do faktycznie używanej pamięci (RSS)
  • sprawdza wykorzystanie pamięci przez proces za pomocą jednej z metod wymienionych w: Wykorzystanie pamięci przez bieżący proces w 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;

/* /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 w górę .

Skompiluj i uruchom:

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

gdzie:

  • 0x1000000000 == 64GiB: 2x fizyczna pamięć RAM mojego komputera 32GiB
  • 0x200000000 == 8GiB: drukuj pamięć co 8GiB, więc powinniśmy uzyskać 4 odbitki przed awarią przy około 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: wymagany dla Linuksa, abyśmy mogli wykonać połączenie mmap większe niż fizyczna pamięć RAM: maksymalna pamięć, którą malloc może przydzielić

Wyjście programu:

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

Status wyjścia:

137

co według reguły liczby 128 + oznacza, że ​​otrzymaliśmy numer sygnału 9, który man 7 signalmówi , że to SIGKILL , który jest wysyłany przez zabójcę braku pamięci w systemie Linux .

Interpretacja wyjściowa:

  • Pamięć wirtualna VSZ pozostaje stała w printf '0x%X\n' 0x40009A4 KiB ~= 64GiB( pswartości w KiB) po mmap.
  • „Rzeczywiste użycie pamięci” RSS rośnie leniwie tylko wtedy, gdy dotykamy stron. Na przykład:
    • przy pierwszym wydruku mamy extra_memory_committed 0, co oznacza, że ​​jeszcze nie dotknęliśmy żadnych stron. RSS to mały plik 1648 KiBprzeznaczony do normalnego uruchamiania programu, takiego jak obszar tekstowy, globały itp.
    • na drugim wydruku napisaliśmy do 8388608 KiB == 8GiBwartości stron. W rezultacie RSS wzrosła dokładnie o 8 GIB do8390256 KiB == 8388608 KiB + 1648 KiB
    • RSS stale rośnie o 8GiB. Ostatni wydruk pokazuje około 24 GiB pamięci, a zanim wydrukowano 32 GiB, zabójca OOM zabił proces

Zobacz także: /unix/35129/need-explanation-on-resident-set-size-virtual-size

Dzienniki zabójców OOM

Nasze dmesgpolecenia pokazały dzienniki zabójców OOM.

Dokładna ich interpretacja została zapytana na:

Pierwszą linią dziennika było:

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

Widzimy więc, co ciekawe, to demon MongoDB, który zawsze działa w moim laptopie w tle, który jako pierwszy wyzwalał zabójcę OOM, prawdopodobnie gdy biedak próbował przydzielić trochę pamięci.

Jednak zabójca OOM niekoniecznie zabija tego, który go obudził.

Po wywołaniu jądro drukuje tabelę lub procesy, w tym 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

a dalej widzimy, że nasze własne małe main.outtak naprawdę zginęło podczas poprzedniego wywołania:

[ 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

Ten dziennik wspomina, score 865jaki proces ten miał, prawdopodobnie najwyższy (najgorszy) wynik zabójcy OOM, jak wspomniano na stronie : /unix/153585/how-does-the-oom-killer-decide-which- Najpierw proces do zabicia

Co ciekawe, wszystko najwyraźniej stało się tak szybko, że zanim uwolniona pamięć została rozliczona, proces oomzostał ponownie obudzony DeadlineMonitor:

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

i tym razem zabił proces Chromium, który zwykle jest normalnym zapisem pamięci mojego komputera:

[ 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

Testowany w Ubuntu 19.04, jądro Linuksa 5.0.0.

Ciro Santilli
źródło
8

Myślę, że wiele już powiedziano o RSS vs VSZ. Z punktu widzenia administratora / programisty / użytkownika, kiedy projektuję / koduję aplikacje, bardziej martwię się o RSZ (pamięć rezydentna), ponieważ kiedy będziesz wyciągał coraz więcej zmiennych (stos), zobaczysz, że ta wartość rośnie. Wypróbuj prosty program do tworzenia pętli przydziału miejsca opartego na malloc i upewnij się, że wypełniłeś dane w tym miejscu malloc. RSS przesuwa się w górę. Jeśli chodzi o VSZ, bardziej chodzi o mapowanie pamięci wirtualnej niż Linux, a jedną z jego podstawowych funkcji są wywodzące się z konwencjonalnych koncepcji systemów operacyjnych. Zarządzanie VSZ odbywa się za pomocą wirtualnego zarządzania pamięcią jądra, aby uzyskać więcej informacji na temat VSZ, zobacz opis Roberta Love'a na mm_struct i vm_struct, które są częścią podstawowej struktury danych task_struct w jądrze.

Anugraha Sinha
źródło
Czy masz na myśli książkę „Linux Kernel Development” autorstwa Love?
benjimin
1

Nie są zarządzane, ale mierzone i prawdopodobnie ograniczone (patrz getrlimitwywołanie systemowe, także na getrlimit (2) ).

RSS oznacza rezydentny rozmiar zestawu (część wirtualnej przestrzeni adresowej siedzącej w pamięci RAM).

Można kwerendy wirtualną przestrzeń adresową procesu 1234 użyciem proc (5) z cat /proc/1234/mapsoraz jego status (w tym zużycie pamięci) thrucat /proc/1234/status

Basile Starynkevitch
źródło
1
Chociaż ten link może odpowiedzieć na pytanie, lepiej jest dołączyć tutaj istotne części odpowiedzi i podać link w celach informacyjnych. Odpowiedzi zawierające tylko łącze mogą stać się nieprawidłowe, jeśli połączona strona ulegnie zmianie. - Z recenzji
Maak
Podałem drugi link. Jeden z nich pozostanie ważny
Basile Starynkevitch