Entendendo o uso de memória no Linux

Por que, afinal, um simples editor de texto do KDE (kedit) ocupa em torno de 25 Megabytes de memória?

Perguntas como essa são bastante comuns entre usuários e administradores de sistemas Linux. Sendo que muitos deles são levados a acreditar que as aplicações desse sistema operacional, especialmente nos ambientes KDE e Gnome, usam uma grande e desnecessária quantidade de memória, baseados nos valores obtidos por ferramentas como o ps.

Enquanto essa afirmação pode ser ou não verdade, ela não deve ser considerada uma regra geral, já que depende exclusivamente das circunstâncias em que o programa está sendo executado. O fato é que, como veremos a seguir, diversos programas são muito mais eficientes no uso da memória do que parecem ser.

Este artigo – uma tradução livre e adaptada do original Understand memory usage on Linux – tenta justificar os resultados do ps referentes à quantidade de memória usada por um processo, e demonstrar através de outra ferramenta uma maneira de se obter valores mais coerentes.

A ferramenta ps

Para usuários que ainda não tiveram muito contato com o console, vulgo “linha de comando”, o ps é uma ferramenta extremamente útil para conseguir informações sobre os processos, como, por exemplo, o PID (número de identificação do processo), o estado de execução e a utilização de recursos (Memória e CPU). Entre os valores possíveis de se obter com o ps estão o VSZ e o RSS, que são, respectivamente, a quantidade de memória virtual (virtual set size) e a quantidade de memória residente (resident set size). Esses valores são geralmente usados para verificar a quantidade de memória ocupada por um processo.

Eis um exemplo de resultado do comando ps, mostrando apenas o processo do programa KEdit:

# ps aux

USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
dbunker 3468 0.0 2.7 25400 14452 ? S 20:19 0:00 kdeinit: kedit

De acordo com esse resultado, o KEdit está ocupando uma quantidade de memória virtual em torno de 25 Megabytes e memória residente em torno de 14 Megabytes (ambos os valores estão em Kilobytes). Existem divergências sobre qual desses valores representa a quantidade real de uso de memória do processo. Usuários e administradores tendem a escolhê-los aleatoriamente, e, no momento, explicar a diferença entre os valores VSZ e RSS não interessa à discussão, já que nenhum deles pode ser considerado o valor exato da quantidade de memória usada pelo KEdit.

Por que o ps está errado?

Dependendo de como se observa o resultado do ps, ele não aponta para a quantidade exata de memória usada pelos processos. O que o seu resultado realmente mostra é a quantidade de memória que usaria determinado processo se ele fosse o único processo em execução. Logicamente, um sistema Linux possui dezenas de processos em execução ao mesmo tempo, o que torna definitivamente os valores VSZ e RSS “errados”. A fim de entender porque razão, é necessário saber como o Linux lida com as bibliotecas compartilhadas nos programas.

Uma biblioteca compartilhada é uma coleção de subprogramas utilizados para facilitar o desenvolvimento de programas, permitindo o compartilhamento e a alteração de código e dados de forma modular. A maior parte dos sistemas operacionais modernos provê bibliotecas que implementam a maioria dos serviços do sistema. Assim sendo, muitos dos programas no Linux utilizam as bilbliotecas compartilhadas para facilitar determinadas funcionalidades.

Por exemplo, o programa KEdit usa várias bibliotecas compartilhadas do KDE (para fazer a interação com outros componentes do KDE), bibliotecas do X Window (para desenhar as imagens e funções de copiar e colar), além das diversas bibliotecas do sistema que realizam as operações básicas. Muitas dessas bibliotecas compartilhadas, especialmente aquelas comumente usadas como a libc, são acessadas por vários programas em execução no sistema. Devido a esse compartilhamento, o Linux é capaz de usar um grande truque: ele carrega uma única cópia da biblioteca compartilhada na memória, e usa essa cópia para todos os programas que fazem referência a ela.

Para bem ou para mal, muitas ferramentas, assim como o ps, não se preocupam com esse comportamento do sistema. Elas simplesmente mostram quanto de memória um processo está ocupando, independente se esta memória está sendo compartilhada com outros processos. Dois programas poderiam, portanto, utilizar a mesma biblioteca compartilhada, e mesmo assim ter o tamanho dessa biblioteca contabilizado na memória total de ambos os processos. Dessa maneira, a quantidade de memória ocupada pela biblioteca está sendo contabilizada duas vezes, gerando resultados enganadores caso não se saiba o que está realmente acontecendo.

Infelizmente, um valor exato da quantidade de memória ocupada por um processo não é algo fácil de se obter. Não só é necessário saber como o sistema funciona, mas também decidir como lidar com algumas questões complexas. Se uma biblioteca compartilhada é usada apenas por um processo, o seu tamanho deve ser contabilizado apenas para esse processo? Se uma biblioteca compartilhada é usada por múltiplos processos, a quantidade de memória ocupada por ela deve ser distribuída entre os diferentes processos, ou apenas ignorada? Não existe uma regra fixa neste caso, pois cada situação terá uma resposta diferente. Assim fica fácil de entender a razão do ps não se esforçar para calcular um resultado mais “correto” do uso de memória, dada a ambigüidade.

Visualizando o mapa da memória

Apesar da imprecisão em relação aos resultados do ps, o Linux fornece um comando para visualizar o mapa da memória de um processo, permitindo assim analisar mais precisamente como um processo está utilizando a memória. Esse comando é o pmap, que com a opção “-d”, produz o seguinte resultado para o processo do KEdit:

Address Kbytes Mode Offset Device Mapping
08048000 40 r-x– 0000000000000000 0fe:00000 kdeinit
08052000 4 rw— 0000000000009000 0fe:00000 kdeinit
08053000 1164 rw— 0000000008053000 000:00000 [ anon ]
40000000 84 r-x– 0000000000000000 0fe:00000 ld-2.3.5.so
40015000 8 rw— 0000000000014000 0fe:00000 ld-2.3.5.so
40017000 4 rw— 0000000040017000 000:00000 [ anon ]
40018000 4 r-x– 0000000000000000 0fe:00000 kedit.so
40019000 4 rw— 0000000000000000 0fe:00000 kedit.so
40027000 252 r-x– 0000000000000000 0fe:00000 libkparts.so.2.1.0
40066000 20 rw— 000000000003e000 0fe:00000 libkparts.so.2.1.0
4006b000 3108 r-x– 0000000000000000 0fe:00000 libkio.so.4.2.0
40374000 116 rw— 0000000000309000 0fe:00000 libkio.so.4.2.0
40391000 8 rw— 0000000040391000 000:00000 [ anon ]
40393000 2644 r-x– 0000000000000000 0fe:00000 libkdeui.so.4.2.0
40628000 164 rw— 0000000000295000 0fe:00000 libkdeui.so.4.2.0
40651000 4 rw— 0000000040651000 000:00000 [ anon ]
40652000 100 r-x– 0000000000000000 0fe:00000 libkdesu.so.4.2.0
4066b000 4 rw— 0000000000019000 0fe:00000 libkdesu.so.4.2.0
4066c000 68 r-x– 0000000000000000 0fe:00000 libkwalletclient.so.1.0.0
4067d000 4 rw— 0000000000011000 0fe:00000 libkwalletclient.so.1.0.0
4067e000 4 rw— 000000004067e000 000:00000 [ anon ]
4067f000 2148 r-x– 0000000000000000 0fe:00000 libkdecore.so.4.2.0
40898000 64 rw— 0000000000219000 0fe:00000 libkdecore.so.4.2.0
408a8000 8 rw— 00000000408a8000 000:00000 [ anon ]
… (cortado) …
mapped: 25404K writeable/private: 2432K shared: 0K

Uma parte do resultado do comando foi omitida, já que é similar ao trecho que foi apresentado. Mesmo sem o resultado completo, é possível verificar alguns pontos interessantes. Um deles a ser observado é que cada biblioteca compartilhada (iniciadas por “lib”) são listadas duas vezes: uma para o segmento de código e outra para o segmento de dados. O segmento de código tem a coluna referente ao modo em “r-x–“, enquanto o segmento de dados possuí o modo “rw—“.

Com base nessa informação, dá para concluir que os segmentos de código das bibliotecas compartilhadas são as que ocupam a maior quantidade de memória, de acordo com a coluna Kbytes. A boa notícia em relação a isso é que justamente essa memória pode ser compartilhada com outros processos em execução. Subtraindo a quantidade de memória ocupada pelas bibliotecas compartilhadas, chega-se ao valor especificado em “writeable/private”, mostrado no final do resultado do pmap. Esse valor pode ser considerado a quantidade real de memória usada pelo processo. Portanto, a quantidade de memória ocupada pelo KEdit, pressupondo que todas as bibliotecas compartilhas foram previamente carregadas, é de aproximadamente 2 Megabytes. Valor definitivamente mais coerente se comparado aos 14 ou 25 Megabytes mostrados pelo comando ps.

Conclusão

A moral da história é que o uso de memória no Linux é uma questão complexa. Não basta apenas rodar o comando ps para saber o que realmente está acontecendo, principalmente quando estiver lidando com programas que criam muitos processos filhos, como é o caso do servidor Web Apache. O comando ps poderá mostrar que cada processo do Apache ocupa 10 Megabytes de memória, quando na realidade essa quantidade é normalmente algo em torno de 1 Megabyte. Esse tipo de informação se torna crítica para realizar uma análise de desempenho do Apache e configurar variáveis como o MaxClients, que determina quantas conexões o servidor Web poderá processar simultaneamente.

Também com base no uso das bibliotecas compartilhadas, reforça-se a idéia de manter apenas aplicações de um único ambiente desktop, como KDE ou Gnome. Caso várias aplicações do Gnome estejam rodando em um ambiente KDE, ou vice-versa, o sistema pagará caro pela quantidade de bibliotecas compartilhadas com a mesma função. Todavia, mantendo aplicações de um único ambiente, o sistema irá reduzir a quantidade de uso de memória, permitindo que o Linux use-a para recursos mais interessantes, como, por exemplo, o cache de arquivos, que acelera consideravelmente o acesso ao sistema de arquivos.

Referências

Devin (04-02-2006). Understand memory usage on Linux. Virtual Threads. Acessado em 15-02-2008.
Wikipédia (09-02-2008). Library (computer science). Acessado em 17-02-2008.

19 comentários sobre “Entendendo o uso de memória no Linux

  1. Complementando, de acordo com esta publicação do Miguel de Icaza, existe uma maneira de se chegar ao mesmo resultado do pmap com a ferramenta top.

    Resumidamente, basta subtrair o valor da coluna RES pela coluna SHR.

    Inclusive essa citação foi extraída dos comentários do artigo original, que teve uma interessante discussão a respeito de outros métodos para se obter resultados semelhantes.

      • Parabéns pelo artigo. Artigo como esses é q fazem a comunidade do software livre não apenas crescer como se desenvolver com qualidade assim como nos traz todos esses avanços que colaborativamente conseguimos e compartilhamos a cada dia.

  2. Heitor, o artigo que você se baseou é excelente.
    O PS realmente não ajuda muito quando queremos saber o que está “sobrecarrengando” o sistema, porém uso o HTOP, que consegue condensar estas informações (inexatas) e responder com “precisão” a memória que está livre e sendo usada no sistema.
    Tem vezes aqui no meu desktop que o FREE mostra a quantidade de memória livre em 0 bytes, porém o HTOP consegue retornar a quantidade real de memória livre…

    Um abraço e parabéns

    • Olá Dailson,

      Sinceramente não conhecia o HTOP e, então, resolvi instalá-lo. Confesso que não encontrei dificuldades para achar um pacote compatível com a minha distribuição.

      Por ser uma ferramenta de console baseada no ncurses, enxerguei em sua interatividade, que é o foco do projeto, um diferencial importante.

      Realmente uma ótima ferramenta. Valeu a dica!

      • Realmente esta ferramenta é desconhecida da maioria dos usuários e administradores. Eu nas minhas aulas e palestras, não deixo ela passar em branco!!! Acho o top muito difícil e chato de se mexer… Mas o HTOP com as teclas de funções você realmente tem muitas facilidades. Já ví também versão para mysql.
        Mas e ai? Qual sua conclusão sobre o HTOP, realmente ele mostra a memória de forma real? Já estudou sobre o assunto?

        Um, grande abraço

        Dailson Fernandes

        • Olá Dailson,

          A princípio o htop mostra as mesmas informações de memória por processo que o top. Nas configurações do programa não encontrei alguma opção para subtrair o valor da memória compartilhada.

          Na minha opinião, a ferramenta possuí vantagens e desvantages em relação ao top. Por exemplo, o top permite redirecionar o resultado para um arquivo, tornando-o útil para adicioná-lo em scripts. Além disso, ele também possuí diversas opções amadurecidas ao longo de anos, senão décadas de desenvolvimento.

          Mas sem nenhuma dúvida o htop é uma excelente ferramenta. Simplifica o gerenciamento, facilita a avaliação dos resultados e traz um pouco de cor para o console.

          Um abraço.

  3. Saudações.

    Gostaria de parabenizar a iniciativa do assunto e sugerir uma continuidade desse abordagem, procurando ressaltar as técnicas de reentrâncias para minimizar o consumo de memória por novos segmentos de código. Que tal dicurtimos os principais modelos de algoritmos conhecidos e quais estariam sendo adotados pelo Kernel do Linux.

    Até.

    • Olá William,

      Agradeço a sugestão e o incentivo. Sempre que for possível, irei reunir informações para abordar esse tema, que assim como você, considero importante e, principalmente, interessante.

      Um abraço.

  4. Muito interessante seu texto. Realmente sempre achei meio complicado calcular a quantidade de memória ocupada por um processo no Linux, principalmente se comparado ao WIndows, que já mostra de forma legível o consumo de memória dos seus processos. Lógico que não é muito fácil confiar no WIndows… 😉

  5. Muito bom o artigo, cara. É bem esclarecedor, principalmente para pessoas que, como eu, trabalham todos os dias com o Apache e precisam de se preocupar com a quantidade de memória que ele usa, conexões simultâneas e etc. Meus parabéns e obrigado pela informação =)

  6. Muito bom! Realmente “joga uma luz” no assunto. O difícil é manter apenas aplicações de um determinado ambiente.. Eu por exemplo, uso o XFCE por sua simplicidade, mas gosto do Nautilus e do gedit (Gnome), e não consigo viver sem o Kile (KDE)…
    parabéns!

  7. Boa tarde

    Só fiquei em dúvida em saber a quem pertence as áreas de memória conforme exemplo abaixo:

    b5e12000 21672 rw— 00000000b5e12000 000:00000 [ anon ]

  8. Realmente sua tradução do artigo foi muito boa. Eu já o tinha lido anteriormente, e graças a ele e aos comentários de alto nível aqui postados tive a idéia de procurar por algum processo que estava sugando mais de 200MB de memória em um servidor que administro, e não é que achei! 🙂

    O ps pode não te dar a idéia exata da memória ocupada pelo processo, mas pelo menos te dá uma noção de quem está ocupando mais memória.

    Valeu.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *