O que é RSS e VSZ no gerenciamento de memória do Linux

331

O que são RSS e VSZ no gerenciamento de memória do Linux? Em um ambiente multithread, como esses dois podem ser gerenciados e rastreados?

tuban
fonte
possível duplicata Compreender registros do oom-assassinas Linux
msangel

Respostas:

499

RSS é o tamanho do conjunto residente e é usado para mostrar quanta memória é alocada para esse processo e está na RAM. Não inclui a memória trocada. Ele inclui memória de bibliotecas compartilhadas, desde que as páginas dessas bibliotecas estejam realmente na memória. Inclui toda a pilha e memória de pilha.

VSZ é o tamanho da memória virtual. Inclui toda a memória que o processo pode acessar, incluindo a memória trocada, a memória alocada, mas não usada, e a memória proveniente de bibliotecas compartilhadas.

Portanto, se o processo A tiver um binário de 500K e estiver vinculado a 2500K de bibliotecas compartilhadas, tiver 200K de alocações de pilha / heap, dos quais 100K estão realmente na memória (o restante é trocado ou não utilizado) e, na verdade, apenas 1000K foi carregado nas bibliotecas compartilhadas e 400K de seu próprio binário:

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

Como parte da memória é compartilhada, muitos processos podem usá-la; portanto, se você adicionar todos os valores de RSS, poderá facilmente ter mais espaço do que o seu sistema.

A memória alocada também pode não estar no RSS até que seja realmente usada pelo programa. Portanto, se seu programa alocou um monte de memória antecipadamente e a utilizou com o tempo, você poderia ver o RSS subindo e o VSZ permanecendo o mesmo.

Há também PSS (tamanho proporcional do conjunto). Essa é uma medida mais recente que rastreia a memória compartilhada como uma proporção usada pelo processo atual. Portanto, se houvesse dois processos usando a mesma biblioteca compartilhada de antes:

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

Todos os threads compartilham o mesmo espaço de endereço; portanto, o RSS, VSZ e PSS para cada thread são idênticos a todos os outros threads no processo. Use ps ou top para visualizar essas informações em linux / unix.

Há muito mais do que isso: para saber mais, verifique as seguintes referências:

Veja também:

jmh
fonte
17
Acredito RSS faz incluir a memória de bibliotecas ligadas dinamicamente. Se houver três processos em uso libxml2.so, a biblioteca compartilhada será contada em cada um de seus RSS, portanto, a soma de seu RSS será mais do que a memória real usada.
Nfm
1
Está correto. Eu corrigi minha resposta, obrigado pelo aviso.
jmh
Estou no ubuntu 16.04, e há um processo java com 1.2G RES e 4.5G VIRT mostrando a partir do topcomando. Este sistema não possui nenhuma troca, swapon --shownão retorna nada. Como você explica isso? Se vsz for swap + bibliotecas compartilhadas, nesse caso, as bibliotecas compartilhadas terão mais de 3.3G? É possível? Apenas realmente confuso ...
Aaron Wang
Eu não tenho certeza. Veja esta resposta sobre o uso da memória virtual Java: stackoverflow.com/a/561450/622115 . Versão curta: O VSZ pode incluir espaço de heap alocado e não usado, além de arquivos mapeados na memória.
jmh
Ótimo. Basta adicionar algo. se você malloc (100 KB), use apenas 1 KB na verdade. O rss é 1K e o vsz é 100K, mesmo se não houver troca aqui.
keniee van
53

RSS é o tamanho do conjunto residente (memória fisicamente residente - atualmente ocupa espaço na memória física da máquina) e VSZ é tamanho da memória virtual (espaço de endereço alocado - isso possui endereços alocados no mapa de memória do processo, mas não há necessariamente nenhum memória real por trás de tudo agora).

Observe que nesses dias de máquinas virtuais comuns, a memória física do ponto de vista da máquina pode não ser realmente a memória física real.

caf
fonte
Importa-se de fornecer mais informações do que o que significa a abreviação?
Pithikos
10

Exemplo mínimo executável

Para que isso faça sentido, você precisa entender o básico da paginação: Como funciona a paginação x86? e, em particular, que o sistema operacional possa alocar memória virtual por meio de tabelas de páginas / sua manutenção de livro de memória interna (memória virtual VSZ) antes que ele realmente tenha um armazenamento de backup na RAM ou no disco (memória residente em RSS).

Agora, para observar isso em ação, vamos criar um programa que:

  • aloca mais RAM do que nossa memória física com mmap
  • grava um byte em cada página para garantir que cada uma dessas páginas passe da memória virtual apenas (VSZ) para a memória realmente usada (RSS)
  • verifica o uso de memória do processo com um dos métodos mencionados em: Uso de memória do processo atual em 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 upstream .

Compile e execute:

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

Onde:

  • 0x1000000000 == 64GiB: 2x a RAM física de 32GiB do meu computador
  • 0x200000000 == 8GiB: imprima a memória a cada 8GiB, portanto, devemos obter 4 impressões antes da falha, em torno de 32GiB
  • echo 1 | sudo tee /proc/sys/vm/overcommit_memory: necessário para o Linux nos permitir fazer uma chamada mmap maior que a RAM física: memória máxima que o malloc pode alocar

Saída do programa:

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 de saída:

137

que pela regra do número de sinal 128 + significa que obtivemos o número do sinal 9, que man 7 signalé SIGKILL , enviado pelo assassino de memória insuficiente do Linux .

Interpretação de saída:

  • A memória virtual VSZ permanece constante em printf '0x%X\n' 0x40009A4 KiB ~= 64GiB(os psvalores estão em KiB) após o mmap.
  • O "uso de memória real" do RSS aumenta preguiçosamente apenas quando tocamos as páginas. Por exemplo:
    • na primeira impressão, temos extra_memory_committed 0, o que significa que ainda não tocamos nenhuma página. RSS é um pequeno 1648 KiBque foi alocado para a inicialização normal do programa, como área de texto, globais, etc.
    • na segunda impressão, escrevemos para o 8388608 KiB == 8GiBvalor de páginas. Como resultado, o RSS aumentou exatamente 8GIB para8390256 KiB == 8388608 KiB + 1648 KiB
    • O RSS continua a aumentar em incrementos de 8GiB. A última impressão mostra cerca de 24 GiB de memória e, antes que 32 GiB pudessem ser impressos, o assassino da OOM interrompeu o processo.

Consulte também: /unix/35129/need-explanation-on-resident-set-size-virtual-size

Logs assassinos de OOM

Nossos dmesgcomandos mostraram os logs do OOM killer.

Uma interpretação exata deles foi solicitada em:

A primeira linha do log foi:

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

Portanto, vemos que, curiosamente, foi o daemon MongoDB que sempre é executado no meu laptop em segundo plano, o que desencadeou o assassino do OOM, provavelmente quando o pobre estava tentando alocar alguma memória.

No entanto, o assassino da OOM não mata necessariamente quem o acordou.

Após a chamada, o kernel imprime uma tabela ou processos, incluindo 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 mais adiante, vemos que nosso pouco main.outfoi morto na invocação anterior:

[ 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

Esse log menciona o score 865que esse processo teve, presumivelmente a maior (pior) pontuação do assassino de OOM, conforme mencionado em: /unix/153585/how-does-the-oom-killer-decide-which- processo para matar primeiro

Curiosamente, tudo aparentemente aconteceu tão rápido que, antes que a memória liberada fosse contabilizada, ela oomfoi despertada novamente pelo DeadlineMonitorprocesso:

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

e desta vez que matou algum processo do Chromium, que geralmente é a memória normal de meus computadores:

[ 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

Testado no Ubuntu 19.04, kernel do Linux 5.0.0.

Ciro Santilli adicionou uma nova foto
fonte
8

Acho que já foi dito muito sobre RSS vs VSZ. Do ponto de vista do administrador / programador / usuário, ao projetar / codificar aplicativos, estou mais preocupado com o RSZ (memória residente), pois e quando você continua puxando mais e mais variáveis ​​(amontoadas), esse valor aumenta. Tente um programa simples para criar alocação de espaço com base em malloc em loop e certifique-se de preencher dados nesse espaço. O RSS continua subindo. No que diz respeito ao VSZ, é mais o mapeamento de memória virtual que o linux faz, e um de seus principais recursos derivados dos conceitos convencionais de sistema operacional. O gerenciamento do VSZ é feito pelo gerenciamento de memória virtual do kernel. Para obter mais informações sobre o VSZ, consulte a descrição de Robert Love em mm_struct e vm_struct, que fazem parte da estrutura básica de dados task_struct no kernel.

Anugraha Sinha
fonte
Você está se referindo ao livro "Linux Kernel Development" de Love?
benjimin 5/03
1

Eles não são gerenciados, mas medidos e possivelmente limitados (consulte a getrlimitchamada do sistema, também no getrlimit (2) ).

RSS significa tamanho do conjunto residente (a parte do seu espaço de endereço virtual localizado na RAM).

Você pode consultar o espaço de endereço virtual do processo 1234 usando proc (5) com cat /proc/1234/mapse seu status (incluindo consumo de memória) atravéscat /proc/1234/status

Basile Starynkevitch
fonte
1
Embora esse link possa responder à pergunta, é melhor incluir aqui as partes essenciais da resposta e fornecer o link para referência. As respostas somente para links podem se tornar inválidas se a página vinculada for alterada. - Da avaliação
Maak
Eu forneci um segundo link. Um deles vai ficar válida
Basile Starynkevitch