Come posso ottenere la quantità di memoria disponibile in modo portabile attraverso le distribuzioni?


12

I file / strumenti standard che riportano la memoria sembrano avere formati diversi su diverse distribuzioni Linux. Ad esempio, su Arch e 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
    

Quindi, come posso portabilmente (solo su distribuzioni Linux) e ottenere in modo affidabile la quantità di memoria - escluso lo scambio - che è disponibile per il mio software da utilizzare in un determinato momento? Presumibilmente è ciò che viene mostrato come "disponibile" e "MemAvailable" nell'output di freee cat /proc/meminfoin Arch, ma come posso ottenere lo stesso in Ubuntu o in un'altra distribuzione?

Risposte:


18

MemAvailableè incluso /proc/meminfodalla versione 3.14 del kernel; è stato aggiunto da commit 34e431b0a . Questo è il fattore determinante nelle variazioni di output che mostri. Il messaggio di commit indica come stimare la memoria disponibile senza MemAvailable:

Attualmente, la quantità di memoria che è disponibile per un nuovo carico di lavoro, senza spingere il sistema in scambio, può essere stimata MemFree, Active(file), Inactive(file), e SReclaimable, così come le "basse" filigrane da /proc/zoneinfo.

Le filigrane basse sono il livello al di sotto del quale il sistema cambierà. Quindi, in assenza di MemAvailablesi può almeno sommare i valori dati per MemFree, Active(file), Inactive(file)e SReclaimable(a seconda di quale sono presenti /proc/meminfo), e sottrarre le filigrane bassi da /proc/zoneinfo. Quest'ultimo elenca anche il numero di pagine libere per zona, che potrebbero essere utili come confronto ...

L'algoritmo completo viene fornito nella patch meminfo.ce sembra ragionevolmente facile da adattare:

  • sommare le filigrane basse in tutte le zone;
  • prende la memoria libera identificata ( MemFree);
  • sottrarre la filigrana bassa (dobbiamo evitare di toccarla per evitare lo scambio);
  • aggiungi la quantità di memoria che possiamo usare dalla cache della pagina (somma di Active(file)e Inactive(file)): è la quantità di memoria utilizzata dalla cache della pagina, meno la metà della cache della pagina o la filigrana bassa, a seconda di quale sia la più piccola;
  • aggiungi la quantità di memoria che possiamo recuperare ( SReclaimable), seguendo lo stesso algoritmo.

Quindi, mettendo tutto insieme, puoi ottenere la memoria disponibile per un nuovo processo 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, bene, quindi almeno dovrebbe essere portabile nella stessa versione del kernel. È qualcosa. Sto testando il tuo suggerimento con il 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/meminfoquale dovrei darmi lo stesso numero stampato due volte. Tuttavia, il secondo numero (la mia comprensione dell'algoritmo che suggerisci) è superiore a quello MemAvailablemostrato in /proc/meminfo. Che cosa sto facendo di sbagliato?
terdon

2
/proc/zoneinfoconta le pagine, che sono per lo più 4KB su amd64; ti manca anche la sicurezza aggiuntiva aggiunta alla cache della pagina e alla memoria recuperabile. Semplificando quest'ultimo, possiamo sottrarre tre volte la filigrana bassa, quindi m-12*low(3 × 4KB) dà il risultato corretto sul mio sistema. (Questa semplificazione sottovaluta la memoria disponibile se la cache della pagina o la memoria esponibile è più piccola del doppio del limite minimo, ma non si desidera utilizzare molta memoria in quella situazione comunque in modo che sembra essere un compromesso ragionevole.)
Stephen Kitt

1
@StephenKitt come faresti per calcolarlo per i kernel più vecchi che non hanno né (file)entires né SReclaimableentry? Su un vecchio centos box con kernel v 2.6.18-348.16.1.el5xen (per uname -r) questo è l'output che ottengo: pastebin.com/iFWiM1kX . Il tuo calcolo tira solo la MemFreeparte
Mitch

@Mitch Non lo so, non sono sicuro che le informazioni disponibili dal tuo vecchio kernel siano sufficienti per determinare con precisione la memoria disponibile (prima dello scambio).
Stephen Kitt,

Grazie a tutti coloro che hanno contribuito a questo thread, è un ottimo riferimento. Il calcolo di MemAvailable è stato leggermente modificato in Linux 4.5. Tuttavia, il nuovo calcolo MemAvailable dovrebbe essere sempre leggermente superiore a (o forse uguale a) quello vecchio, quindi dovrebbe essere sicuro usare il vecchio calcolo in tutti i casi. gitlab.com/procps-ng/procps/issues/42
sourcejedi

7

Mentre la risposta di Stephen è perfettamente sufficiente ed errori dal lato della cautela, ho deciso di scrivere la logica completa, compresi i confronti minimi. Le informazioni vengono prima lette da / proc / meminfo e memorizzate in una variabile in modo che i dettagli della memoria siano coerenti.

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

Il risultato memorizzato nella variabile è in byte.


Mentre questa risposta implementa il calcolo nel commit 34e431b0a, la risposta di Stephen Kitt ha fornito una stima più accurata su 2 macchine su 5 che ho testato. Su tutte e 5 le macchine, entrambe le risposte hanno dato stime più grandi di MemAvailable lette direttamente da / proc / meminfo. Probabilmente un modo più sicuro è ottenere il più piccolo tra i 2 e moltiplicare per 0,95 o giù di lì.
toddwz
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.