Descobrir quanta memória RAM um processo Linux usa não é uma questão simples, especialmente quando a memória compartilhada precisa ser considerada. Felizmente, o pmap
comando ajuda você a entender tudo.
Índice
Em sistemas operacionais modernos , cada processo vive em sua própria região alocada de memória ou espaço de alocação . Os limites da região alocada não são mapeados diretamente para endereços de hardware físico. O sistema operacional cria um espaço de memória virtual para cada processo e atua como uma camada de abstração mapeando a memória virtual para a memória física.
O kernel mantém uma tabela de tradução para cada processo, e esta é acessada pela CPU . Quando o kernel altera o processo em execução em um núcleo de CPU específico , ele atualiza a tabela de conversão que une processos e núcleos de CPU.
Há benefícios para este esquema. O uso da memória é um pouco encapsulado e protegido por sandbox para cada processo na área de usuário. Um processo apenas “vê” a memória em termos de endereços de memória virtual. Isso significa que ele só pode trabalhar com a memória que lhe foi dada pelo sistema operacional. A menos que tenha acesso a alguma memória compartilhada, ele não conhece nem tem acesso à memória alocada para outros processos.
A abstração da memória física baseada em hardware em endereços de memória virtual permite que o kernel altere o endereço físico para o qual alguma memória virtual está mapeada. Ele pode trocar a memória para o disco alterando o endereço real para o qual uma região de memória virtual aponta. Ele também pode adiar o fornecimento de memória física até que seja realmente necessário.
Contanto que as solicitações de leitura ou gravação de memória sejam atendidas conforme solicitado, o kernel está livre para fazer malabarismos com a tabela de mapeamento como achar melhor.
A tabela de mapeamento e o conceito de “RAM sob demanda” abrem a possibilidade de memória compartilhada . O kernel tentará evitar carregar a mesma coisa na memória mais de uma vez. Por exemplo, ele carregará uma biblioteca compartilhada na memória uma vez e a mapeará para os diferentes processos que precisam usá-la. Cada um dos processos terá seu próprio endereço exclusivo para a biblioteca compartilhada, mas todos apontarão para o mesmo local real.
Se a região compartilhada da memória for gravável, o kernel usa um esquema chamado copy-on-write. Se um processo grava na memória compartilhada e os outros processos que compartilham essa memória não devem ver as alterações, uma cópia da memória compartilhada é criada no ponto da solicitação de gravação.
O kernel Linux 2.6.32, lançado em dezembro de 2009, deu ao Linux um recurso chamado “Kernel SamePage Merging”. Isso significa que o Linux pode detectar regiões idênticas de dados em diferentes espaços de endereço. Imagine uma série de máquinas virtuais rodando em um único computador e todas as máquinas virtuais rodando no mesmo sistema operacional. Usando um modelo de memória compartilhada e copy-on-write, a sobrecarga no computador host pode ser drasticamente reduzida.
Tudo isso torna o manuseio de memória no Linux sofisticado e o mais otimizado possível. Mas essa sofisticação torna difícil olhar para um processo e saber qual é realmente seu uso de memória.
O kernel expõe muito do que está fazendo com a RAM através de dois pseudo-arquivos no pseudo-sistema de informações do sistema “/proc”. Existem dois arquivos por processo, nomeados para o ID do processo ou PID de cada processo: “/proc/maps” e “/proc//smaps”.
A pmap
ferramenta lê as informações desses arquivos e exibe os resultados na janela do terminal. Será óbvio que precisamos fornecer o PID do processo em que estamos interessados sempre que usarmos pmap
.
Existem várias maneiras de encontrar o PID de um processo . Aqui está o código-fonte de um programa trivial que usaremos em nossos exemplos. Ele está escrito em C. Tudo o que ele faz é imprimir uma mensagem na janela do terminal e esperar que o usuário pressione a tecla “Enter”.
#include <stdio.h> int main(int argc, char *argv[]) { printf("Programa de teste Geek How-To."); getc(stdin); } // fim do principal
O programa foi compilado para um executável chamado pm
usando o gcc
compilador:
gcc -o pm pm.c
Como o programa vai esperar que o usuário aperte “Enter”, ele vai ficar rodando o tempo que quisermos.
./PM
O programa é iniciado, imprime a mensagem e aguarda o pressionamento de tecla. Agora podemos procurar seu PID. O ps
comando lista os processos em execução. A -e
opção (mostrar todos os processos) ps
lista todos os processos. Vamos canalizar a saída grep
e filtrar as entradas que têm “pm” em seu nome.
ps -e | grep pm
Isso lista todas as entradas com “pm” em qualquer lugar em seus nomes.
Podemos ser mais específicos usando o pidof
comando. Damos pidof
o nome do processo em que estamos interessados na linha de comando e ele tenta encontrar uma correspondência. Se uma correspondência for encontrada, pidof
imprime o PID do processo de correspondência.
pidof pm
O pidof
método é mais organizado quando você sabe o nome do processo, mas o ps
método funcionará mesmo se souber apenas parte do nome do processo.
Com nosso programa de teste em execução, e uma vez que identificamos seu PID, podemos usar o pmap assim:
pmap 40919
Os mapeamentos de memória para o processo são listados para nós.
Aqui está a saída completa do comando:
40919: ./pm 000056059f06c000 4K r---- pm 000056059f06d000 4K rx-- pm 000056059f06e000 4K r---- pm 000056059f06f000 4K r---- pm 000056059f070000 4K rw --- pm 000056059fc39000 132K rw--- [anônimo] 00007f97a3edb000 8K rw --- [ anon ] 00007f97a3edd000 160K r---- libc.so.6 00007f97a3f05000 1616K rx-- libc.so.6 00007f97a4099000 352K r---- libc.so.6 00007f97a40f1000 4K ----- libc.so.6 00007f97a40f2000 16K r---- libc.so.6 00007f97a40f6000 8K rw --- libc.so.6 00007f97a40f8000 60K rw --- [ anon ] 00007f97a4116000 4K r---- ld-linux-x86-64.so.2 00007f97a4117000 160K rx--ld-linux-x86-64.so.2 00007f97a413f000 40K r---- ld-linux-x86-64.so.2 00007f97a4149000 8K r---- ld-linux-x86-64.so.2 00007f97a414b000 8K rw --- ld-linux-x86-64.so.2 00007ffca0e7e000 132K rw --- [ pilha ] 00007ffca0fe1000 16K r---- [anônimo] 00007ffca0fe5000 8K rx-- [anônimo] ffffffffff600000 4K --x-- [ anon ] total de 2.756 mil
A primeira linha é o nome do processo e seu PID. Cada uma das outras linhas mostra um endereço de memória mapeado e a quantidade de memória nesse endereço, expressa em kilobytes. Os próximos cinco caracteres de cada linha são chamados de permissões de memória virtual . As permissões válidas são:
A informação final em cada linha é o nome da fonte do mapeamento. Pode ser um nome de processo, nome de biblioteca ou nome de sistema, como pilha ou heap.
A -x
opção (estendida) fornece duas colunas extras.
pmap -x 40919
As colunas recebem títulos. Já vimos as colunas “Endereço”, “Kbytes”, “Modo” e “Mapeamento”. As novas colunas são chamadas de “RSS” e “Dirty”.
Aqui está a saída completa:
40919: ./pm Endereço Kbytes RSS Mapeamento de modo sujo 000056059f06c000 4 4 0 r---- pm 000056059f06d000 4 4 0 rx-- pm 000056059f06e000 4 4 0 r---- pm 000056059f06f000 4 4 4 r---- pm 000056059f070000 4 4 4 rw --- pm 000056059fc39000 132 4 4 rw --- [ anon ] 00007f97a3edb000 8 4 4 rw --- [ anon ] 00007f97a3edd000 160 160 0 r---- libc.so.6 00007f97a3f05000 1616 788 0 rx-- libc.so.6 00007f97a4099000 352 64 0 r---- libc.so.6 00007f97a40f1000 4 0 0 ----- libc.so.6 00007f97a40f2000 16 16 16 r---- libc.so.6 00007f97a40f6000 8 8 8 rw --- libc.so.6 00007f97a40f8000 60 28 28 rw --- [ anon ] 00007f97a4116000 4 4 0 r---- ld-linux-x86-64.so.2 00007f97a4117000 160 160 0 rx-- ld-linux-x86-64.so.2 00007f97a413f000 40 40 0 r---- ld-linux-x86-64.so.2 00007f97a4149000 8 8 8 r---- ld-linux-x86-64.so.2 00007f97a414b000 8 8 8 rw--- ld-linux-x86-64.so.2 00007ffca0e7e000 132 12 12 rw --- [ pilha ] 00007ffca0fe1000 16 0 0 r ---- [ anon ] 00007ffca0fe5000 8 4 0 rx-- [anônimo] ffffffffff600000 4 0 0 --x-- [ anon ] ----- ------- ------- ------- KB total 2756 1328 96
O -X
(ainda mais do que estendido) adiciona colunas adicionais à saída. Observe o “X” maiúsculo. Outra opção chamada -XX
(ainda mais que -X
) mostra que tudo pmap
pode ser obtido do kernel. Como -X
é um subconjunto de -XX
, descreveremos a saída de -XX
.
pmap -XX 40919
A saída envolve horrivelmente em uma janela de terminal e é praticamente indecifrável. Aqui está a saída completa:
40919: ./pm Endereço Perm Offset Dispositivo Inode Tamanho KernelPageSize MMUPageSize Rss Pss Shared_Clean Shared_Dirty Private_Clean Private_Dirty Referenciado Anônimo LazyFree AnonHugePages ShmemPmdMapped FilePmdMapped Shared_Hugetlb Private_Hugetlb Swap SwapPss Bloqueado THPeligible VmFlags Mapping 56059f06c000 r--p 00000000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm 56059f06d000 r-xp 00001000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 rd ex sr mw me dw sd pm 56059f06e000 r--p 00002000 08:03 393304 4 4 4 4 4 0 0 4 0 4 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd pm 56059f06f000 r--p 00002000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw ac sd pm 56059f070000 rw-p 00003000 08:03 393304 4 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr sr mw me dw ac sd pm 56059fc39000 rw-p 00000000 00:00 0 132 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd [heap] 7f97a3edb000 rw-p 00000000 00:00 0 8 4 4 4 4 0 0 0 4 4 4 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd 7f97a3edd000 r--p 00000000 08:03 264328 160 4 4 160 4 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me sd libc.so.6 7f97a3f05000 r-xp 00028000 08:03 264328 1616 4 4 788 32 788 0 0 0 788 0 0 0 0 0 0 0 0 0 0 0 rd ex sr mw me sd libc.so.6 7f97a4099000 r--p 001bc000 08:03 264328 352 4 4 64 1 64 0 0 0 64 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me sd libc.so.6 7f97a40f1000 ---p 00214000 08:03 264328 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 mr mw me sd libc.so.6 7f97a40f2000 r--p 00214000 08:03 264328 16 4 4 16 16 0 0 0 16 16 16 0 0 0 0 0 0 0 0 0 0 rd mr mw me ac sd libc.so.6 7f97a40f6000 rw-p 00218000 08:03 264328 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr sr mw me ac sd libc.so.6 7f97a40f8000 rw-p 00000000 00:00 0 60 4 4 28 28 0 0 0 28 28 28 0 0 0 0 0 0 0 0 0 0 rd wr mr mw me ac sd 7f97a4116000 r--p 00000000 08:03 264305 4 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 rd sr mw me dw sd ld-linux-x86-64.so.2 7f97a4117000 r-xp 00001000 08:03 264305 160 4 4 160 11 160 0 0 0 160 0 0 0 0 0 0 0 0 0 0 0 rd ex sr mw me dw sd ld-linux-x86-64.so.2 7f97a413f000 r--p 00029000 08:03 264305 40 4 4 40 1 40 0 0 0 40 0 0 0 0 0 0 0 0 0 0 0 0 rd mr mw me dw sd ld-linux-x86-64.so.2 7f97a4149000 r--p 00032000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd sr mw me dw ac sd ld-linux-x86-64.so.2 7f97a414b000 rw-p 00034000 08:03 264305 8 4 4 8 8 0 0 0 8 8 8 0 0 0 0 0 0 0 0 0 0 rd wr sr mw me dw ac sd ld-linux-x86-64.so.2 7ffca0e7e000 rw-p 00000000 00:00 0 132 4 4 12 12 0 0 0 12 12 12 0 0 0 0 0 0 0 0 0 0 rd wr sr mw me gd ac [stack] 7ffca0fe1000 r--p 00000000 00:00 0 16 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 rd mr pf io de dd sd [vvar] 7ffca0fe5000 r-xp 00000000 00:00 0 8 4 4 4 0 4 0 0 0 4 0 0 0 0 0 0 0 0 0 0 0 rd ex mr mw me de sd [vdso] ffffffffff600000 --xp 00000000 00:00 0 4 4 4 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 ex [vsyscall] ==== ========================= ==== === ============ == ================================================== ===== ======== ===================================== === ============================= ==== ============= = ========== 2756 92 92 1328 157 1220 0 12 96 1328 96 0 0 0 0 0 0 0 0 0 0 KB
Tem muita informação aqui. Isto é o que as colunas mantêm:
lsblk
comando.MADV_FREE
. Essas páginas foram marcadas como disponíveis para serem liberadas e recuperadas, mesmo que possam ter alterações não escritas nelas. No entanto, se ocorrerem alterações subsequentes após o MADV_FREE
ter sido definido no mapeamento de memória, o MADV_FREE
sinalizador será removido e as páginas não serão recuperadas até que as alterações sejam gravadas.Os VmFlags — sinalizadores de memória virtual — serão um subconjunto da lista a seguir.
madvise()
função.)E trabalhar de trás para frente a partir de tabelas de dados para entender o que realmente está acontecendo é difícil. Mas pelo menos pmap
lhe dá uma visão completa para que você tenha a melhor chance de descobrir o que precisa saber.
É interessante notar que nosso programa de exemplo compilou para um executável binário de 16 KB e ainda está usando (ou compartilhando) cerca de 2756 KB de memória, quase inteiramente devido a bibliotecas de tempo de execução.
Um truque legal final é que você pode usar pmap
e os pidof
comandos juntos, combinando as ações de encontrar o PID do processo e passá-lo pmap
em um comando:
pmap $(pidof pm)
Muitos aplicativos de limpeza estão disponíveis para Windows ao longo dos anos, mas hoje em…
Seu PlayStation 4 está congelado? Seus jogos favoritos continuam travando? Reiniciar seu PS4 pode resolver…
A popularidade das mensagens de texto significou aprender uma forma totalmente nova de comunicação. Você…
A foto dos "Pilares da Criação" tirada pelo Telescópio Espacial Hubble é uma das fotos…
O Proton Drive saiu de seu estágio beta há algumas semanas, mas o aplicativo real…
Para ver suas fotos mais de perto ou para uma edição precisa , você pode…