Como identificar o consumo de memória de um processo no Linux?

- por Sergio Prado

Categorias: Linux Tags: ,

Então você precisa identificar o consumo de memória de um processo no Linux. Parece uma pergunta fácil de responder, não é verdade? Parece, mas não é!

Todo processo no Linux tem um arquivo no /proc que descreve detalhadamente seu uso de memória:

$ sudo cat /proc/1/smaps
7f3ba235d000-7f3ba2367000 r-xp 00000000 08:06 26877393                   /lib/x86_64-linux-gnu/libnss_files-2.19.so
Size:                 40 kB
Rss:                  12 kB
Pss:                   0 kB
Shared_Clean:         12 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:           12 kB
Anonymous:             0 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
VmFlags: rd ex mr mw me sd 
7f3ba2367000-7f3ba2566000 ---p 0000a000 08:06 26877393                   /lib/x86_64-linux-gnu/libnss_files-2.19.so
Size:               2044 kB
Rss:                   0 kB
Pss:                   0 kB
Shared_Clean:          0 kB
Shared_Dirty:          0 kB
Private_Clean:         0 kB
Private_Dirty:         0 kB
Referenced:            0 kB
Anonymous:             0 kB
AnonHugePages:         0 kB
Swap:                  0 kB
KernelPageSize:        4 kB
MMUPageSize:           4 kB
Locked:                0 kB
...

Alguns comandos, como o top, utilizam o arquivo acima para totalizar e exibir o consumo de memória de forma resumida:

$ top
top - 17:55:01 up 1 day, 11:17,  6 users,  load average: 0,26, 0,30, 0,30
Tasks: 328 total,   3 running, 321 sleeping,   3 stopped,   1 zombie
%Cpu(s):  0,9 us,  0,5 sy,  0,0 ni, 98,4 id,  0,1 wa,  0,0 hi,  0,0 si,  0,0 st
KiB Mem:  16400272 total, 14886920 used,  1513352 free,  1301036 buffers
KiB Swap: 31249404 total,   119108 used, 31130296 free.  5523180 cached Mem
 
  PID USER      PR  NI    VIRT    RES    SHR S  %CPU %MEM     TIME+ COMMAND                                                                       
16494 sprado    20   0  520304  34068   9648 S   3,0  0,2   0:08.12 chrome
 2056 root      20   0 1250340 718208 119328 S   2,7  4,4 110:36.08 Xorg
14582 sprado    20   0  659684   7560   4008 S   2,0  0,0  46:41.06 pulseaudio
18009 sprado    20   0 3168096 2,060g 2,023g S   2,0 13,2 934:51.85 vmware-vmx
19252 sprado    20   0  669952  24980  11036 S   1,3  0,2   2:21.39 gnome-terminal
14700 sprado    20   0 1757284 130748  32932 S   1,0  0,8  61:18.61 compiz
...

Os campos VIRT, RES e SHR na saída do comando acima estão relacionados ao uso de memória, e falaremos sobre eles daqui a pouco. Mas já adianto que nenhum destes campos representa o uso real de memória física de um processo! Na verdade, não existe nenhum comando no Linux que vai te retornar esta informação, porque não é possível! O quê? Como assim???

É isso mesmo. E tudo é culpa de um pedacinho de hardware chamado MMU. Mas vamos começar do começo…

O Linux trabalha com memória virtual. Existe um chip chamado MMU (Memory Management Unit) localizado entre o processador e a memória RAM. Todo e qualquer acesso à memória passa por ele.

Os processos acessam a memória através de endereços virtuais. Durante o acesso à memória, a MMU consulta uma tabela de mapeamento (page table) e faz a conversão dos endereços virtuais do processos para os endereços físicos da RAM.

E para que serve tudo isso? Para muitas coisas, como por exemplo SWAP, controle de acesso, segurança e compartilhamento de memória. Se você tiver mais curiosidade sobre o funcionamento da MMU e suas vantagens, consulte o artigo “O Linux em sistemas sem MMU e o uClinux“.

Voltando à saída do comando top, o valor do campo VIRT (Virtual Memory Size) representa a quantidade total de memória virtual mapeada para um processo. Por exemplo, o chrome possui em torno de 520MB de memória virtual mapeada para ele. Mas isso não significa que tudo isso está mapeado em memória física. Por exemplo, parte deste mapeamento virtual pode estar em SWAP (disco).

Por outro lado, o campo RES (Resident Memory Size) indica a quantidade de memória mapeada fisicamente para o processo (aproximadamente 34MB no exemplo do chrome). Mas este campo também não indica a quantidade de memória física total utilizada pelo processo! Como assim???

Outros processos podem estar compartilhando memória com ele. Por exemplo, quando o kernel carrega o código de uma biblioteca para a memória RAM, ele pode mapear esta mesma região de memória física para todos os processos que querem utilizar a biblioteca, economizando assim memória RAM, porque a biblioteca é carregada uma vez só e compartilhada por múltiplos processos. Um exemplo clássico é a biblioteca do sistema (libc).

Na prática, isso significa que, se eu encerrar a execução do chrome, não serão liberados os 34MB de memória exibidos na listagem do comando top, porque parte desta memória é compartilhada com outros processos. Portanto, este campo não serve como referência para a memória física utilizada (unica e exclusivamente) pelo processo.

Por fim, o campo SHR (Shared Memory Size) representa a quantidade de memória que este processo está compartilhando com outros processos. Também não serve diretamente para o propósito de identificar a quantidade de memória física consumida pelo processo.

Sim, o buraco é muito mais embaixo. Na prática, só é possível identificar o uso aproximado de memória de um processo!

Uma forma é identificar a quantidade de memória física consumida de forma exclusiva pelo processo e somar com uma proporção da quantidade de memória compartilhada com outros processos. É basicamente isso que o comando smem faz!

$ smem -r
  PID User     Command                         Swap      USS      PSS      RSS 
14925 sprado   /usr/lib/x86_64-linux-gnu/z        0   413216   413479   417144 
15048 sprado   /opt/google/chrome/chrome          0   383364   395453   425564 
20161 sprado   /opt/google/chrome/chrome -        0   236084   245963   286940 
18867 sprado   /opt/google/chrome/chrome -        0   231452   235478   270032 
20015 sprado   /opt/google/chrome/chrome -        0   144484   148761   184072 
14796 sprado   /home/sprado/.dropbox-dist/        0   138012   138268   144440 
15289 sprado   /opt/google/chrome/chrome -        0   120904   123651   153916 
14700 sprado   compiz                             0   102500   111868   130964 
15494 sprado   /opt/google/chrome/chrome -        0    89572    93431   128036 
16554 sprado   /opt/google/chrome/chrome -        0    83612    90005   127016 
13176 sprado   /opt/google/chrome/chrome -        0    59864    62301    89460 
14721 sprado   nautilus -n                        0    23956    49293    83968 
17185 sprado   /usr/lib/vmware/bin/vmware         0    45268    48599    61124 
15301 sprado   /opt/google/chrome/chrome -        0    45820    48035    75116 
14387 sprado   /usr/lib/x86_64-linux-gnu/h        0    41320    42137    49604 
14669 sprado   /usr/lib/evolution/evolutio        0    37432    37524    40840 
15291 sprado   /opt/google/chrome/chrome -        0    32632    35128    64268 
18391 sprado   gedit /home/sprado/Dropbox/        0    29296    31248    42696 
20714 sprado   /usr/bin/python3 /usr/share        0    22836    23055    26532 
15296 sprado   /opt/google/chrome/chrome -        0    18536    21235    50972 
14401 sprado   /usr/lib/unity/unity-panel-        0    19944    20604    29572 
17225 sprado   /usr/lib/vmware/bin/vmware-        0    15152    16640    24724 
19252 sprado   gnome-terminal                     0    15148    16224    25624 
20850 sprado   vim lwip/src/arch/lpc17xx_4        0    15384    15904    18336 
17148 sprado   /usr/bin/unity-scope-loader        0    14872    15090    18664 
15298 sprado   /opt/google/chrome/chrome -        0    11672    13538    38664

O campo USS (Unique Set Size) representa a quantidade de memória física mapeada de forma exclusiva para o processo, e somando mais uma proporção da memória compartilhada com outros processos tem-se o campo PSS (Proportional Set Size), que é o que você vai ter de mais perto do consumo de memória de um processo no Linux!

Satisfeito? :)

Happy hacking!

Sergio Prado

  • Excelente artigo Sergio.

    Gosto da saída do /proc/PID/status acho mais “humano” e a parte Vm* tem bastante informação legal e separadinha.

    Sempre tomei o pmap como ajuda, e o ps_mem(https://github.com/pixelb/ps_mem) mas este usei apenas no meu notebook, pura informação do /proc em Python.

    Abraços

    • Legal esta ferramenta ps_mem! Não conhecia!

    • Leonardo Graboski Veiga

      Gostei muito do artigo, Sérgio, obrigado por compartilhar estas informações. Também achei muito interessante a dica do /proc/pid/status do Cleiton – fui verificar um processo com o smaps e a saída dele ficou muito grande.

      Por um lado, achei interessante a saída do “smaps” pois dá pra ver quais bibliotecas o processo está usando e o consumo detalhado pra cada uma delas, por outro lado é tanta informação impressa que o “status” ajudou a sintetizar a informação. Enfim, usei as duas informações de maneira complementar.

      Pra nós que costumamos usar Linux embarcado e portanto geralmente não usamos swap, além de podermos estimar de antemão a quantidade (ao menos aproximada) de processos que o sistema utilizará em campo (será mesmo? ou será que ainda assim isto é impraticável?), parece ser um pouco mais simples de realizar um diagnóstico de memória do que num sistema Linux mais complexo.

      Abraço

      • Olá Leonardo! Mesmo em sistemas sem SWAP, o comportamento é o mesmo, tudo por causa da memória virtual, por exemplo quando o kernel utiliza mecanismos de alocação e mapeamento de memória como copy-on-write e demand fault paging. Um abraço!

  • George Tavares

    Excelente post Sergio!
    Só gostaria de complementar, que o gerenciamento de memória no linux desconsiderando um processo especifico, apresenta a caracteristica de usar toda a memória RAM como buffer de cache de IO. Assim, um linux rodando a um tempinho ja vai apresentar que toda a memoria esta ocupada, entretanto muito dessa memoria estara neste buffer de cache . Assim que voce dispara um novo processo, esse buffer comeca a ser requisitado a fim de evitar o uso de swap.

    • É verdade George! A saída do comando free também precisa ser interpretada para identificar a quantidade real de memória livre do sistema. Obrigado por complementar o artigo. Um abraço!

  • Willian Henrique

    Muito legal o artigo.

    Alguém sabe uma forma de verificar a taxa de leitura e escrita na memória?
    Algo em Mb/s.
    Abraços,

    • Olá William! Boa pergunta! Acho que vai ser dificil encontrar uma ferramenta que meça o throughput de memória em todos os casos, pois a ferramenta pode depender de diversos fatores (arquitetura da CPU, níveis de cache, uso de MMU, etc). Me parece que as duas mais utilizadas são a bandwidth [1] e a pmbw [2].

      [1] http://zsmith.co/bandwidth.html
      [2] https://panthema.net/2013/pmbw/

      Um abraço!

Navegue
Creative Commons Este trabalho de Sergio Prado é licenciado pelo
Creative Commons BY-NC-SA 3.0.