¿Cómo puedo obtener la cantidad de memoria disponible de forma portátil en todas las distribuciones?


12

Los archivos / herramientas estándar que informan sobre la memoria parecen tener diferentes formatos en diferentes distribuciones de Linux. Por ejemplo, en Arch y Ubuntu.

  • Arco

    $ free
                  total        used        free      shared  buff/cache   available
    Mem:        8169312     3870392     2648348       97884     1650572     4110336
    Swap:      16777212      389588    16387624
    
    
    $ head /proc/meminfo 
    MemTotal:        8169312 kB
    MemFree:         2625668 kB
    MemAvailable:    4088520 kB
    Buffers:          239688 kB
    Cached:          1224520 kB
    SwapCached:        17452 kB
    Active:          4074548 kB
    Inactive:        1035716 kB
    Active(anon):    3247948 kB
    Inactive(anon):   497684 kB
    
  • Ubuntu

    $ free
                 total       used       free     shared    buffers     cached
    Mem:      80642828   69076080   11566748    3063796     150688   58358264
    -/+ buffers/cache:   10567128   70075700
    Swap:     20971516    5828472   15143044
    
    
    $ head /proc/meminfo 
    MemTotal:       80642828 kB
    MemFree:        11565936 kB
    Buffers:          150688 kB
    Cached:         58358264 kB
    SwapCached:      2173912 kB
    Active:         27305364 kB
    Inactive:       40004480 kB
    Active(anon):    7584320 kB
    Inactive(anon):  4280400 kB
    Active(file):   19721044 kB
    

Entonces, ¿cómo puedo obtener de forma portátil (solo en las distribuciones de Linux) y obtener de forma confiable la cantidad de memoria, excluyendo el intercambio, que está disponible para que mi software la use en un momento determinado? Presumiblemente, eso es lo que se muestra como "disponible" y "MemAvailable" en la salida freey cat /proc/meminfoen Arch, pero ¿cómo obtengo lo mismo en Ubuntu u otra distribución?

Respuestas:


18

MemAvailablese incluye /proc/meminfodesde la versión 3.14 del núcleo; fue agregado por commit 34e431b0a . Ese es el factor determinante en las variaciones de salida que muestra. El mensaje de confirmación indica cómo calcular la memoria disponible sin MemAvailable:

Actualmente, la cantidad de memoria que está disponible para una nueva carga de trabajo, sin empujar el sistema en el intercambio, puede estimarse a partir de MemFree, Active(file), Inactive(file), y SReclaimable, así como las marcas de agua "bajas" de /proc/zoneinfo.

Las marcas de agua bajas son el nivel por debajo del cual se intercambiará el sistema. Por lo tanto, en ausencia de MemAvailableal menos puede sumar los valores dados para MemFree, Active(file), Inactive(file)y SReclaimable(el que están presentes en /proc/meminfo), y restar las marcas de agua de baja /proc/zoneinfo. Este último también enumera el número de páginas libres por zona, que podrían ser útiles como comparación ...

El algoritmo completo se proporciona en el parche meminfo.cy parece razonablemente fácil de adaptar:

  • suma las marcas de agua bajas en todas las zonas;
  • tomar la memoria libre identificada ( MemFree);
  • reste la marca de agua baja (debemos evitar tocar eso para evitar el intercambio);
  • agregue la cantidad de memoria que podemos usar desde el caché de la página (suma de Active(file)y Inactive(file)): esa es la cantidad de memoria utilizada por el caché de la página, menos la mitad del caché de la página o la marca de agua baja, lo que sea menor;
  • agregue la cantidad de memoria que podemos reclamar ( SReclaimable), siguiendo el mismo algoritmo.

Entonces, juntando todo esto, puede obtener la memoria disponible para un nuevo proceso con:

awk -v low=$(grep low /proc/zoneinfo | awk '{k+=$2}END{print k}') \
 '{a[$1]=$2}
  END{ 
   print a["MemFree:"]+a["Active(file):"]+a["Inactive(file):"]+a["SReclaimable:"]-(12*low); 
  }' /proc/meminfo 

Ah, bien, así que al menos debería ser portátil en la misma versión del kernel. Eso es algo. Estoy probando su sugerencia con la awk -v low=$(grep low /proc/zoneinfo | awk '{k+=$2}END{print k}') '{a[$1]=$2}END{m=a["MemFree:"]+a["Active(file):"]+a["Inactive(file):"]+a["SReclaimable:"]; print a["MemAvailable:"],m-low}' /proc/meminfocual debería darme el mismo número impreso dos veces. Sin embargo, el segundo número (según entiendo el algoritmo que sugiere) es más alto que el que se MemAvailablemuestra en /proc/meminfo. ¿Qué estoy haciendo mal?
terdon

2
/proc/zoneinfocuenta páginas, que en su mayoría tienen un tamaño de 4KB amd64; también le falta la seguridad adicional agregada al caché de la página y la memoria recuperable. Simplificando esto último, podemos restar la marca de agua baja tres veces, por lo que m-12*low(3 × 4KB) da el resultado correcto en mi sistema. (Esta simplificación subestima la memoria disponible si la memoria caché de la página o la memoria recuperable es menor que el doble de la marca de agua baja, pero de todos modos no querrá usar mucha memoria en esa situación, por lo que parece ser un compromiso razonable).
Stephen Kitt

1
@StephenKitt, ¿cómo harías para calcularlo para núcleos más antiguos que no tienen (file)entradas ni la SReclaimableentrada? En una caja de centos anterior con kernel v 2.6.18-348.16.1.el5xen (per uname -r), esta es la salida que obtengo: pastebin.com/iFWiM1kX . Su cálculo solo tira de la MemFreeparte
Mitch

@ Mitch No lo sé, no estoy seguro de que la información disponible de su núcleo anterior sea suficiente para determinar la memoria disponible (antes del intercambio) con precisión.
Stephen Kitt

Gracias a todos los que contribuyeron a este hilo, es una gran referencia. El cálculo de MemAvailable se ha ajustado ligeramente en Linux 4.5. Sin embargo, el nuevo cálculo MemAvailable siempre debe ser ligeramente más alto (o tal vez el mismo) que el anterior, por lo que debe ser seguro usar el cálculo antiguo en todos los casos. gitlab.com/procps-ng/procps/issues/42
sourcejedi

7

Si bien la respuesta de Stephen es perfectamente suficiente y se equivoca por el lado de la precaución, decidí escribir la lógica completa, incluidas las comparaciones mínimas. La información se lee primero de / proc / meminfo y se almacena en una variable para que los detalles de la memoria sean consistentes.

LOW_WATERMARK=$(awk '$1 == "low" {LOW_WATERMARK += $2} END {print LOW_WATERMARK * 4096}' /proc/zoneinfo)

MEMINFO=$(</proc/meminfo)

MEMINFO_MEMFREE=$(echo "${MEMINFO}" | awk '$1 == "MemFree:" {print $2 * 1024}')
MEMINFO_FILE=$(echo "${MEMINFO}" | awk '{MEMINFO[$1]=$2} END {print (MEMINFO["Active(file):"] + MEMINFO["Inactive(file):"]) * 1024}')
MEMINFO_SRECLAIMABLE=$(echo "${MEMINFO}" | awk '$1 == "SReclaimable:" {print $2 * 1024}')

MEMINFO_MEMAVAILABLE=$((
  MEMINFO_MEMFREE - LOW_WATERMARK
  + MEMINFO_FILE - ((MEMINFO_FILE/2) < LOW_WATERMARK ? (MEMINFO_FILE/2) : LOW_WATERMARK)
  + MEMINFO_SRECLAIMABLE - ((MEMINFO_SRECLAIMABLE/2) < LOW_WATERMARK ? (MEMINFO_SRECLAIMABLE/2) : LOW_WATERMARK)
))

if [[ "${MEMINFO_MEMAVAILABLE}" -le 0 ]]
then
  MEMINFO_MEMAVAILABLE=0
fi

El resultado almacenado en variable está en bytes.


Si bien esta respuesta implementa el cálculo en el commit 34e431b0a, la respuesta de Stephen Kitt proporcionó una estimación más precisa en 2 máquinas de las 5 que probé. En las 5 máquinas, ambas respuestas dieron estimaciones más grandes que las que MemAvailable leyó directamente desde / proc / meminfo. Probablemente una forma más segura es obtener el más pequeño entre los 2, y multiplicar por 0,95 más o menos.
toddwz
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.