Determinar correctamente el uso de memoria en Linux

63

Estoy un poco confundido sobre algunos de los resultados que estoy viendo de ps y gratis .

En mi servidor, este es el resultado de free -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

Comprendo que Linux gestiona la memoria es que almacenará el uso del disco en la RAM, de modo que cada acceso posterior sea más rápido. Creo que esto está indicado por las columnas "en caché". Además, se almacenan varios búferes en la RAM, indicados en la columna "búferes".

Entonces, si entiendo correctamente, se supone que el uso "real" es el valor "usado" de "- / + buffers / cache", o 561 en este caso.

Asumiendo que todo eso es correcto, la parte que me arroja es el resultado de ps aux.

Según tengo entendido, los psresultados son que la sexta columna (RSS) representa el tamaño en kilobytes que el proceso usa para la memoria.

Entonces cuando ejecuto este comando:

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

¿No debería ser el resultado la columna "usada" de "- / + buffers / cache" de free -m?

Entonces, ¿cómo puedo determinar correctamente el uso de memoria de un proceso en Linux? Aparentemente mi lógica es defectuosa.

GoldenNewby
fuente
Esta pregunta es bastante popular y creo que debería compartir una respuesta del htopautor a una pregunta similar que tuve el otro día ... Cómo calcular el uso de memoria desde / proc / meminfo (como htop)
tgogos

Respuestas:

58

Este exacta misma pregunta se hizo en serverfault el otro día :-)

El sistema de memoria virtual de Linux no es tan simple. No puede simplemente sumar todos los campos RSS y obtener el valor informado usedpor free. Hay muchas razones para esto, pero llegaré a algunas de las más importantes.

  • Cuando un proceso se bifurca, tanto el padre como el hijo se mostrarán con el mismo RSS. Sin embargo, Linux emplea copy-on-writepara que ambos procesos realmente estén usando la misma memoria. Solo cuando uno de los procesos modifica la memoria, en realidad se duplicará. Entonces esto hará que el freenúmero sea más pequeño que la topsuma RSS.

  • El valor RSS no incluye memoria compartida. Debido a que la memoria compartida no es propiedad de ningún proceso, topno la incluye en RSS. Entonces esto hará que el freenúmero sea mayor que la topsuma RSS.

Patricio
fuente
1
Esta es la mejor respuesta que he recibido en cualquier sitio de intercambio de pila hasta la fecha. Así que específicamente lo que quería saber. Es especialmente preciso para mi situación porque estoy lidiando con un programa que escribí que se bifurca de procesos, pero la mayor parte de la huella está en las bibliotecas que usan.
GoldenNewby
El problema con esta respuesta es que calcular la suma de RSS y SHR a menudo da mucho menos memoria que la utilizada. Por ejemplo, en un VPS que tengo, la memoria utilizada es de 380 MB, mientras que la suma de todos los RSS y SHR es de 90 MB.
user239558
2
@ user239558 Como mencioné en la respuesta, hay muchas razones por las que los números no cuadran, solo enumeré 2 de ellos. Hay muchos otros números; caché, losa, páginas enormes, etc.
Patrick
2
Probablemente años después de que respondiste esto, todavía tengo (al menos) una confusión. Usted dijo que el valor RSS no incluye la memoria compartida, pero esta respuesta dice que "sí incluye la memoria de las bibliotecas compartidas siempre que las páginas de esas bibliotecas estén realmente en la memoria". Ahora no sé en quién creer ... Tal vez me estoy perdiendo algunas diferencias sutiles aquí ...
Naitree
1
@Naitree "shared library"! = "Memoria compartida". memoria compartida es cosas como shmgeto mmap. La redacción en torno a la memoria es muy complicada. Usar la palabra incorrecta en el lugar equivocado puede arruinar totalmente el significado de una oración.
Patrick
30

Si está buscando números de memoria que sumen, eche un vistazo a smem :

smem es una herramienta que puede proporcionar numerosos informes sobre el uso de memoria en sistemas Linux. A diferencia de las herramientas existentes, smem puede informar el tamaño de conjunto proporcional (PSS), que es una representación más significativa de la cantidad de memoria utilizada por las bibliotecas y aplicaciones en un sistema de memoria virtual.

Debido a que grandes porciones de memoria física generalmente se comparten entre múltiples aplicaciones, la medida estándar de uso de memoria conocida como tamaño de conjunto residente (RSS) sobreestimará significativamente el uso de memoria. En cambio, PSS mide el "reparto justo" de cada aplicación de cada área compartida para dar una medida realista.

Por ejemplo aquí:

# 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 

También lo PSSes la columna interesante aquí porque tiene en cuenta la memoria compartida.
A diferencia de RSSesto es significativo sumarlo. Aquí obtenemos un total de 654Mb para procesos de usuario.

La salida de todo el sistema informa sobre el 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 

Entonces, 1Gb de RAM total = 654Mb de procesos de usuario + 346Mb kernel mem + 16Mb gratis
(más o menos Mb)

En general, aproximadamente la mitad de la memoria se usa para caché (494Mb).

Pregunta adicional: ¿qué es la caché de userland vs la caché del kernel aquí?


por cierto para algo intento visual:

# smem  --pie=name

ingrese la descripción de la imagen aquí

exprimir
fuente
14

Una herramienta realmente buena es la pmapque enumera el uso actual de la memoria para un determinado proceso:

pmap -d PID

Para obtener más información al respecto, consulte la página del manual man pmapy también eche un vistazo a las 20 herramientas de monitoreo del sistema Linux que todo SysAdmin debe conocer , que enumeran las excelentes herramientas que siempre uso para obtener información sobre mi caja de Linux.

ByteNudger
fuente
Esa es una herramienta bastante buena, pero en realidad no resuelve mi problema. Estoy tratando de descubrir cómo determinar efectivamente el uso de memoria "real" en el servidor.
GoldenNewby
3
@GoldenNewby No existe el uso de memoria "real" de un proceso. El uso real de la memoria del sistema es lo que freete dice.
Gilles 'SO- deja de ser malvado'
pmap -x PIDtambién incluye una columna RSS que a menudo es bastante útil para tener una idea de dónde topproviene la suma RSS de un proceso (como se observa, por ejemplo, a través de).
maxschlepzig
10

Corre arriba, presiona hpara obtener ayuda y luego fagrega campos. puede agregar los siguientes campos:

  • RSS cantidad de memoria física que usa la aplicación
  • CODE cantidad total de memoria que usa el código ejecutable del proceso
  • DATA - cantidad total de memoria (kb) dedicada a los datos y la pila de un proceso

Entre estos 3 deberías tener resultados bastante precisos. También puede usar reemplazos más detallados para la parte superior que recomiendo htopo atop.

Editar: Casi se me olvida si quieres información realmente detallada. Encuentre el PID y obtenga el siguiente archivo.

PID=123

cat /proc/123/status

Edición 2: si puede encontrarlo o tenerlo en el libro:

Optimización del rendimiento de Linux: una guía práctica para las herramientas de rendimiento de Linux

-tiene una sección Capítulo 5: Herramientas de rendimiento: memoria específica del proceso -tiene mucha más información de la que nunca desearía.

2bc
fuente
Bueno, la parte superior por defecto tiene el tamaño RSS del proceso. Top da resultados idénticos a los de "ps aux" en mi ejemplo. Mi pregunta es, ¿cómo es que el RSS combinado de todos los procesos es mucho más alto que el uso de memoria "activa" en todo el servidor?
GoldenNewby
5

psle brinda la cantidad de memoria utilizada por cada proceso. Parte de esa memoria son archivos mmapped, que cuentan bajo caché. Parte de esa memoria (especialmente el código) se comparte con otros procesos, por lo que si suma los valores RSS, se cuenta varias veces.

No hay una respuesta correcta a “¿cuánta memoria usa este proceso?”, Porque no depende solo del proceso, sino que también depende del entorno. Hay muchos valores diferentes que podría llamar el "uso de memoria" del proceso, y no coinciden ni se suman porque están contando cosas diferentes.

Gilles 'SO- deja de ser malvado'
fuente
4

Como otros han señalado correctamente, es difícil controlar la memoria real utilizada por un proceso, con regiones compartidas y archivos mmap'ed y demás.

Si eres un experimentador, puedes ejecutar valgrind y macizo . Esto puede ser un poco pesado para el usuario casual, pero con el tiempo obtendrá una idea del comportamiento de la memoria de una aplicación. Si una aplicación malloc () es exactamente lo que necesita, esto le dará una buena representación del uso real de la memoria dinámica de un proceso. Pero este experimento puede ser "envenenado".

Para complicar las cosas, Linux le permite comprometer en exceso su memoria. Cuando malloc () memoria, estás indicando tu intención de consumir memoria. Pero la asignación realmente no sucede hasta que escribe un byte en una nueva página de su "RAM" asignada. Puedes probarte esto escribiendo y ejecutando un pequeño programa en 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 $!

Ejecuta esto en una máquina con menos de 16 GB de RAM y, ¡listo !, acabas de obtener 16 GB de memoria! (no en realidad no).

Observe topque ve "VIRT" como 16.004G pero% MEM es 0.0

Ejecute esto de nuevo con valgrind:

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

Y el macizo dice "suma de todos los alocs () = 16GB". Entonces eso no es muy interesante.

PERO, si lo ejecutas en un proceso sensato :

# 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

Y aquí vemos (muy empíricamente y con mucha confianza) que el compilador asignó 77 KB de almacenamiento dinámico.

¿Por qué esforzarse tanto para obtener solo el uso del montón? Debido a que todos los objetos compartidos y las secciones de texto que usa un proceso (en este ejemplo, el compilador) no son terriblemente interesantes. Son gastos generales constantes para un proceso. De hecho, las invocaciones posteriores del proceso casi son "gratis".

Además, compare y contraste lo siguiente:

MMAP () un archivo de 1GB. Su tamaño de VMS será de 1 + GB. Pero su Tamaño de conjunto residente solo serán las partes del archivo en las que causó que se pagine (al desreferenciar un puntero a esa región). Y si "lee" todo el archivo, para cuando llegue al final, es posible que el núcleo ya haya paginado los comienzos (esto es fácil de hacer porque el núcleo sabe exactamente cómo / dónde reemplazar esas páginas si se desreferencia de nuevo ) En cualquier caso, ni VMSize ni RSS son un buen indicador del "uso" de su memoria. En realidad no has malloc () editado nada.

Por el contrario, Malloc () y toque MUCHA memoria, hasta que su memoria se cambie al disco. Entonces su memoria asignada ahora excede su RSS. Aquí, su VMSize podría comenzar a decirle algo (su proceso posee más memoria de la que realmente reside en su RAM). Pero aún es difícil diferenciar entre VM que son páginas compartidas y VM que son datos intercambiados.

Aquí es donde Valgrind / Macizo se pone interesante. Le muestra lo que ha asignado intencionalmente (independientemente del estado de sus páginas).

Miles F. Bintz II
fuente
Tengo una pregunta para ti. Tengo un proceso que mlock () es todos sus archivos mmap'ed. ¿Hay alguna manera de determinar qué cantidad de esta memoria se usa activamente? ¿Cuánto se ha leído o escrito en, por ejemplo, el último minuto o dos?
Michael Martinez
2

Pruebe esto: le dará la RAM total realmente utilizada por todo el proceso que se ejecuta en MB

ps -eo size,pid,user,command --sort -size | awk '
  { hr=$1/1024 ; printf("%13.2f Mb ",hr) } 
  { for ( x=4 ; x<=NF ; x++ ) { printf("%s ",$x) } print "" }
  ' | awk '{total=total + $1} END {print total}'
Vineeth
fuente
El sizereportado por pstiene poca relación con el uso de memoria real. Es el tamaño virtual de cada proceso que no necesariamente se asigna a la memoria. Tampoco incluye algunos segmentos que están asignados.
Matt
-2

Le mostrará cuánta memoria usuario por usuario.

#!/bin/bash
total_mem=0

printf "%-10s%-10s\n" User MemUsage

while read u m
do
        [[ $old_user != $u ]] && {  printf "%-10s%-0.1f\n" $old_user $total_mem;
                                    total_mem=0; }
        total_mem="$(echo $m + $total_mem | bc)"
        old_user=$u

done < <(ps --no-headers -eo user,%mem| sort -k1)

#EOF
Vinood NK Maheshwari
fuente
-3

Use este comando para encontrar la utilización de la memoria en%.

Memoria utilizada:

grep Mem | awk '{print $3/$2 * 100.0}'

memoria libre

grep Mem | awk '{print $4/$2 * 100.0}'
Arjun K Mukundan
fuente
3
Errr, esto no hará nada. grepsimplemente se sentará allí esperando la entrada.
mattdm
1
Esto debería haber sidofree -m | grep Mem | awk '{print $3/$2 * 100.0}'
vjangus