Descubrir cuánta RAM usa un proceso de Linux no es un asunto simple, especialmente cuando se necesita considerar la memoria compartida. Afortunadamente, el pmap
comando te ayuda a darle sentido a todo.
En los sistemas operativos modernos , cada proceso vive en su propia región asignada de memoria o espacio de asignación . Los límites de la región asignada no se asignan directamente a las direcciones de hardware físico. El sistema operativo crea un espacio de memoria virtual para cada proceso y actúa como una capa de abstracción que asigna la memoria virtual a la memoria física.
El núcleo mantiene una tabla de traducción para cada proceso, y la CPU accede a ella . Cuando el kernel cambia el proceso que se ejecuta en un núcleo de CPU en particular , actualiza la tabla de traducción que une los procesos y los núcleos de CPU.
Hay beneficios en este esquema. El uso de la memoria está algo encapsulado y aislado para cada proceso en el área de usuario. Un proceso solo «ve» la memoria en términos de las direcciones de memoria virtual. Esto significa que solo puede funcionar con la memoria que le ha dado el sistema operativo. A menos que tenga acceso a alguna memoria compartida, no conoce ni tiene acceso a la memoria asignada a otros procesos.
La abstracción de la memoria física basada en hardware en direcciones de memoria virtual permite que el kernel cambie la dirección física a la que se asigna alguna memoria virtual. Puede cambiar la memoria al disco cambiando la dirección real a la que apunta una región de memoria virtual. También puede diferir el suministro de memoria física hasta que realmente se requiera.
Siempre que las solicitudes para leer o escribir en la memoria se atiendan a medida que se solicitan, el núcleo es libre de hacer malabarismos con la tabla de mapeo como mejor le parezca.
La tabla de mapeo y el concepto de “RAM bajo demanda” abren la posibilidad de memoria compartida . El núcleo intentará evitar cargar lo mismo en la memoria más de una vez. Por ejemplo, cargará una biblioteca compartida en la memoria una vez y la asignará a los diferentes procesos que necesitan usarla. Cada uno de los procesos tendrá su propia dirección única para la biblioteca compartida, pero todos apuntarán a la misma ubicación real.
Si se puede escribir en la región compartida de la memoria, el kernel usa un esquema llamado copia en escritura. Si un proceso escribe en la memoria compartida y se supone que los otros procesos que comparten esa memoria no deben ver los cambios, se crea una copia de la memoria compartida en el punto de la solicitud de escritura.
El kernel de Linux 2.6.32, lanzado en diciembre de 2009, le dio a Linux una función llamada «Kernel SamePage Merging». Esto significa que Linux puede detectar regiones idénticas de datos en diferentes espacios de direcciones. Imagine una serie de máquinas virtuales que se ejecutan en una sola computadora y todas las máquinas virtuales ejecutan el mismo sistema operativo. Usando un modelo de memoria compartida y copia en escritura, la sobrecarga en la computadora host puede reducirse drásticamente.
Todo lo cual hace que el manejo de la memoria en Linux sea sofisticado y óptimo. Pero esa sofisticación hace que sea difícil observar un proceso y saber cuál es realmente su uso de memoria.
El kernel expone mucho de lo que está haciendo con la RAM a través de dos pseudo-archivos en el pseudo-sistema de archivos de información del sistema “/proc”. Hay dos archivos por proceso, con el nombre del ID de proceso o PID de cada proceso: “/proc/maps” y “/proc//smaps”.
La pmap
herramienta lee la información de estos archivos y muestra los resultados en la ventana del terminal. Será obvio que debemos proporcionar el PID del proceso que nos interesa cada vez que usamos pmap
.
Hay varias formas de encontrar el PID de un proceso . Aquí está el código fuente de un programa trivial que usaremos en nuestros ejemplos. Está escrito en C. Todo lo que hace es imprimir un mensaje en la ventana de la terminal y esperar a que el usuario presione la tecla «Enter».
#incluir <stdio.h> int main(int argc, char *argv[]) { printf("Programa de prueba How-To Geek"); getc(entrada estándar); } // fin de principal
El programa fue compilado a un ejecutable llamado pm
usando el gcc
compilador:
gcc -o pm pm.c
Debido a que el programa esperará a que el usuario presione «Enter», permanecerá ejecutándose todo el tiempo que queramos.
./pm
El programa se inicia, imprime el mensaje y espera la pulsación de la tecla. Ahora podemos buscar su PID. El ps
comando enumera los procesos en ejecución. La -e
opción (mostrar todos los procesos) hace una ps
lista de todos los procesos. Canalizaremos la salida grep
y filtraremos las entradas que tengan «pm» en su nombre.
pd-e | grep pm
Esto enumera todas las entradas con «pm» en cualquier lugar de sus nombres.
Podemos ser más específicos usando el pidof
comando. Damos pidof
el nombre del proceso que nos interesa en la línea de comando e intenta encontrar una coincidencia. Si se encuentra una coincidencia, pidof
imprime el PID del proceso de coincidencia.
pido de la tarde
El pidof
método es más ordenado cuando conoce el nombre del proceso, pero el ps
método funcionará incluso si solo conoce parte del nombre del proceso.
Con nuestro programa de prueba en ejecución, y una vez que hayamos identificado su PID, podemos usar pmap de esta manera:
pmapa 40919
Las asignaciones de memoria para el proceso se enumeran para nosotros.
Aquí está el resultado completo del comando:
40919: ./pm 000056059f06c000 4K r---- pm 000056059f06d000 4K rx-- pm 000056059f06e000 4K r---- pm 000056059f06f000 4K r---- pm 000056059f070000 4K rw--- p.m. 000056059fc39000 132K rw--- [anónimo] 00007f97a3edb000 8K rw--- [anónimo] 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--- [anónimo] 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--- [pila] 00007ffca0fe1000 16K r---- [anónimo] 00007ffca0fe5000 8K rx-- [anónimo] ffffffffff600000 4K --x-- [anónimo] total 2756K
La primera línea es el nombre del proceso y su PID. Cada una de las otras líneas muestra una dirección de memoria asignada y la cantidad de memoria en esa dirección, expresada en kilobytes. Los siguientes cinco caracteres de cada línea se denominan permisos de memoria virtual . Los permisos válidos son:
La información final en cada línea es el nombre de la fuente del mapeo. Puede ser un nombre de proceso, un nombre de biblioteca o un nombre de sistema, como pila o montón.
La -x
opción (extendida) proporciona dos columnas adicionales.
pmap -x 40919
Las columnas reciben títulos. Ya hemos visto las columnas «Dirección», «Kbytes», «Modo» y «Mapeo». Las nuevas columnas se llaman «RSS» y «Dirty».
Aquí está la salida completa:
40919: ./pm Dirección Kbytes RSS Modo sucio Mapeo 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--- [anónimo] 00007f97a3edb000 8 4 4 rw--- [anónimo] 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--- [anónimo] 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--- [pila] 00007ffca0fe1000 16 0 0 r---- [ anónimo ] 00007ffca0fe5000 8 4 0 rx-- [anónimo] ffffffffff600000 4 0 0 --x-- [anónimo] ------- ------- ------- ------- kB totales 2756 1328 96
El -X
(incluso más que extendido) agrega columnas adicionales a la salida. Tenga en cuenta la «X» mayúscula. Otra opción llamada -XX
(incluso más que -X
) le muestra todo lo que pmap
puede obtener del kernel. Como -X
es un subconjunto de -XX
, describiremos la salida de -XX
.
pmap -XX 40919
La salida se envuelve horriblemente en una ventana de terminal y es prácticamente indescifrable. Aquí está la salida completa:
40919: ./pm Dirección Perm Desplazamiento Dispositivo Tamaño de inodo 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 Asignación 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 mr 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 mr 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 mr 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 señor 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 0 rd wr mr 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 mr 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 mr 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 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 0 rd mr 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 0 rd wr mr 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 mr mw me gd ac [pila] 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
Hay mucha información aquí. Esto es lo que contienen las columnas:
lsblk
comando.MADV_FREE
. Estas páginas se han marcado como disponibles para ser liberadas y reclamadas, aunque pueden tener cambios no escritos en ellas. Sin embargo, si se producen cambios posteriores después de MADV_FREE
que se haya establecido en la asignación de memoria, el MADV_FREE
indicador se elimina y las páginas no se recuperarán hasta que se escriban los cambios.Las VmFlags (marcas de memoria virtual) serán un subconjunto de la siguiente lista.
madvise()
función).Y trabajar hacia atrás a partir de tablas de datos para comprender lo que realmente está sucediendo es difícil. Pero al menos pmap
le brinda una imagen completa para que tenga la mejor oportunidad de descubrir lo que necesita saber.
Es interesante notar que nuestro programa de ejemplo se compiló en un ejecutable binario de 16 KB y, sin embargo, usa (o comparte) unos 2756 KB de memoria, casi en su totalidad debido a las bibliotecas de tiempo de ejecución.
Un buen truco final es que puede usar pmap
y los pidof
comandos juntos, combinando las acciones de encontrar el PID del proceso y pasarlo a pmap
un solo comando:
pmap $(pidof pm)
El mundo del gaming ha experimentado un crecimiento exponencial en los últimos años. La…
Stokkete/Shutterstock.com ¿Sigue utilizando una unidad flash USB obsoleta para almacenar sus archivos? ¿Por qué no…
LG Los fabricantes siempre intentan mejorar el rendimiento de imagen de los monitores. Como resultado,…
Patty Chan/Shutterstock.com Si cree en lo que ve en las redes sociales, puede pensar en…
Seksan.TH/Shutterstock.com Los servicios de suscripción como Netflix, Game Pass y Spotify nos permiten consumir tantas…
fatmawati achmad zaenuri/Shutterstock El acceso a Internet, oa cualquier otra red, se rige por la…