Determinando corretamente o uso de memória no Linux

Determinando corretamente o uso de memória no Linux

Estou um pouco confuso com alguns dos resultados que estou vendoobs:elivre.

No meu servidor, este é o resultado defree -m

[root@server ~]# free -m
             total       used       free     shared    buffers     cached
Mem:          2048       2033         14          0         73       1398
-/+ buffers/cache:        561       1486
Swap:         2047         11       2036

Meu entendimento de como o Linux gerencia a memória é que ele armazenará o uso do disco na RAM, para que cada acesso subsequente seja mais rápido. Acredito que isso seja indicado pelas colunas "em cache". Além disso, vários buffers são armazenados na RAM, indicados na coluna “buffers”.

Então, se bem entendi, o uso "real" deve ser o valor "usado" de "-/+ buffers/cache", ou 561 neste caso.

Então, supondo que tudo isso esteja correto, a parte que me surpreende são os resultados de ps aux.

Meu entendimento dos psresultados é que a 6ª coluna (RSS) representa o tamanho em kilobytes que o processo usa para memória.

Então, quando executo este comando:

[root@server ~]# ps aux | awk '{sum+=$6} END {print sum / 1024}'
1475.52

O resultado não deveria ser a coluna "usada" de "-/+ buffers/cache" de free -m?

Então, como posso determinar corretamente o uso de memória de um processo no Linux? Aparentemente minha lógica é falha.

Responder1

Copie/cole descaradamente minha resposta defalha no servidoroutro dia mesmo :-)

O sistema de memória virtual Linux não é tão simples. Você não pode simplesmente somar todos os campos RSS e obter o valor relatado usedpor free. Há muitas razões para isso, mas abordarei algumas das maiores.

  • Quando um processo se bifurca, tanto o pai quanto o filho serão exibidos com o mesmo RSS. No entanto, o Linux emprega cópia na gravação para que ambos os processos realmente usem a mesma memória. Somente quando um dos processos modificar a memória ela será realmente duplicada.
    Isso fará com que o freenúmero seja menor que a topsoma do RSS.

  • O valor RSS não inclui memória compartilhada. Como a memória compartilhada não pertence a nenhum processo, topnão a inclui no RSS.
    Isso fará com que o freenúmero seja maior que a topsoma do RSS.

Existem muitos outros motivos pelos quais os números podem não bater. Esta resposta está apenas tentando deixar claro que o gerenciamento de memória é muito complexo e você não pode simplesmente adicionar/subtrair valores individuais para obter o uso total da memória.

Responder2

Se você está procurando números de memória que se somam, dê uma olhada emsmem:

smem é uma ferramenta que pode fornecer vários relatórios sobre o uso de memória em sistemas Linux. Ao contrário das ferramentas existentes, o smem pode relatar o tamanho do conjunto proporcional (PSS), que é uma representação mais significativa da quantidade de memória usada por bibliotecas e aplicativos em um sistema de memória virtual.

Como grandes porções de memória física são normalmente compartilhadas entre vários aplicativos, a medida padrão de uso de memória conhecida como tamanho do conjunto residente (RSS) superestimará significativamente o uso de memória. Em vez disso, o PSS mede a “parcela justa” de cada aplicação em cada área compartilhada para fornecer uma medida realista.

Por exemplo aqui:

# smem -t
  PID User     Command                         Swap      USS      PSS      RSS
...
10593 root     /usr/lib/chromium-browser/c        0    22868    26439    49364 
11500 root     /usr/lib/chromium-browser/c        0    22612    26486    49732 
10474 browser  /usr/lib/chromium-browser/c        0    39232    43806    61560 
 7777 user     /usr/lib/thunderbird/thunde        0    89652    91118   102756 
-------------------------------------------------------------------------------
  118 4                                       40364   594228   653873  1153092 

A coluna aqui também PSSé interessante porque leva em consideração a memória compartilhada.
Ao contrário, RSSé significativo somar. Obtemos um total de 654 MB para processos de usuário aqui.

A saída de todo o sistema informa sobre o resto:

# smem -tw
Area                           Used      Cache   Noncache 
firmware/hardware                 0          0          0 
kernel image                      0          0          0 
kernel dynamic memory        345784     297092      48692 
userspace memory             654056     181076     472980 
free memory                   15828      15828          0 
----------------------------------------------------------
                            1015668     493996     521672 

Portanto, 1 Gb de RAM total = 654 Mb de processos de usuário + 346 Mb de memória do kernel + 16 Mb livres
(mais ou menos alguns Mb)

No geral, cerca de metade da memória é usada para cache (494Mb).

Pergunta bônus: o que é cache do usuário versus cache do kernel aqui?


aliás, para algo visual, tente:

# smem  --pie=name

insira a descrição da imagem aqui

Responder3

Uma ferramenta realmente boa é pmaplistar o uso atual de memória para um determinado processo:

pmap -d PID

Para obter mais informações sobre isso, consulte a página de manual man pmape também dê uma olhada em20 ferramentas de monitoramento de sistema Linux que todo SysAdmin deve conhecer, que lista ótimas ferramentas que sempre uso para obter informações sobre minha caixa Linux.

Responder4

Como outros apontaram corretamente, é difícil controlar a memória real usada por um processo, com regiões compartilhadas, arquivos mmap'ed e outros enfeites.

Se você é um experimentador, você pode executarvalgrind e maciço. Isso pode ficar um pouco pesado para o usuário casual, mas você terá uma ideia do comportamento da memória de um aplicativo ao longo do tempo. Se um aplicativo malloc() for exatamente o que ele precisa, isso fornecerá uma boa representação do uso real da memória dinâmica de um processo. Mas esta experiência pode ser “envenenada”.

Para complicar as coisas, o Linux permite que vocêcomprometer demaissua memória. Ao usar a memória malloc(), você está declarando sua intenção de consumir memória. Mas a alocação realmente não acontece até que você grave um byte em uma nova página da sua "RAM" alocada. Você pode provar isso escrevendo e executando um pequeno programa em C como este:

// test.c
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
int main() {
    void *p;
    sleep(5)
    p = malloc(16ULL*1024*1024*1024);
    printf("p = %p\n", p);
    sleep(30);
    return 0;
}

# Shell:
cc test.c -o test && ./test &
top -p $!

Execute isso em uma máquina com menos de 16 GB de RAM e, pronto!, você acabou de ganhar 16 GB de memória! (Não, na verdade não).

Observe que topvocê vê "VIRT" como 16.004G, mas% MEM é 0,0

Execute isso novamente com valgrind:

# Shell:
valgrind --tool=massif ./test &
sleep 36
ms_print massif.out.$! | head -n 30

E o maciço diz "soma de todos os allocs() = 16GB". Então isso não é muito interessante.

MAS, se você executá-lo em umsãoprocesso:

# Shell:
rm test test.o
valgrind --tool=massif cc test.c -o test &
sleep 3
ms_print massif.out.$! | head -n 30

--------------------------------------------------------------------------------
Command:            cc test.c -o test
Massif arguments:   (none)
ms_print arguments: massif.out.23988
--------------------------------------------------------------------------------


    KB
77.33^                                                                       :
     |                                                                      #:
     |                                                                :@::@:#:
     |                                                           :::::@@::@:#:
     |                                                         @:: :::@@::@:#:
     |                                                     ::::@:: :::@@::@:#:
     |                                             ::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                                            @::@:::@:::::@:: :::@@::@:#:
     |                      :@@@@@@@@@@@@@@@@@@@@:@::@:::@:::::@:: :::@@::@:#:
     |                      :@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                    :@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |                   :@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |              :@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |          :::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |        :::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
     |       ::::::::@::::@@:@@                  :@::@:::@:::::@:: :::@@::@:#:
   0 +----------------------------------------------------------------------->Mi
     0                                                                   1.140

E aqui vemos (muito empiricamente e com uma confiança muito alta) que o compilador alocou 77 KB de heap.

Por que tentar tanto obter apenas o uso do heap? Porque todos os objetos compartilhados e seções de texto que um processo usa (neste exemplo, o compilador) não são muito interessantes. Eles são sobrecarga constante para um processo. Na verdade, as invocações subsequentes do processo são quase “de graça”.

Além disso, compare e contraste o seguinte:

MMAP() um arquivo de 1 GB. Seu VMSize será 1+GB. Mas seu tamanho do conjunto residente será apenas as partes do arquivo que você fez com que fossem paginadas (desreferenciando um ponteiro para essa região). E se você "ler" o arquivo inteiro, quando chegar ao final, o kernel já poderá ter paginado o início (isso é fácil de fazer porque o kernel sabe exatamente como/onde substituir essas páginas se forem desreferenciadas novamente ). Em ambos os casos, nem VMSize nem RSS são um bom indicador do "uso" de sua memória. Na verdade, você não fez malloc() nada.

Por outro lado, Malloc() e toque em MUITA memória - até que sua memória seja trocada para o disco. Portanto, sua memória alocada agora excede seu RSS. Aqui, seu VMSize pode começar a lhe dizer algo (seu processo possui mais memória do que realmente reside em sua RAM). Mas ainda é difícil diferenciar entre VM que são páginas compartilhadas e VM que são dados trocados.

É aqui que valgrind/massif se torna interessante. Isso mostra o que você temintencionalmentealocado (independentemente do estado de suas páginas).

informação relacionada