Wie kann ich die Menge des verfügbaren Speichers portabel über Distributionen hinweg portieren?

11

Die Standarddateien / -tools, die Speicher melden, scheinen auf verschiedenen Linux-Distributionen unterschiedliche Formate zu haben. Zum Beispiel auf Arch und Ubuntu.

  • Bogen

    $ 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
    

Wie kann ich also portabel (nur über Linux-Distributionen hinweg) und zuverlässig die Speichermenge abrufen - ohne Swap -, die für meine Software zu einem bestimmten Zeitpunkt verfügbar ist? Vermutlich wird dies in der Ausgabe von freeund cat /proc/meminfoin Arch als "verfügbar" und "MemAvailable" angezeigt, aber wie bekomme ich dasselbe in Ubuntu oder einer anderen Distribution?

terdon
quelle

Antworten:

17

MemAvailableist /proc/meminfoseit Version 3.14 des Kernels enthalten; Es wurde durch Commit 34e431b0a hinzugefügt . Dies ist der entscheidende Faktor für die von Ihnen angezeigten Ausgabevariationen. Die Festschreibungsnachricht gibt an, wie der verfügbare Speicher geschätzt werden kann, ohne MemAvailable:

Die Menge an Speicher zur Zeit, die für eine neue Arbeitsbelastung, ohne dass die Taste System Swap zur Verfügung steht, kann von geschätzt werden MemFree, Active(file), Inactive(file), und SReclaimable, wie auch die „low“ Wasserzeichen aus /proc/zoneinfo.

Die niedrigen Wasserzeichen sind die Ebene, unter der das System tauscht. In Abwesenheit von können MemAvailableSie also zumindest die Werte für MemFree, und (je nachdem Active(file), was in vorhanden ist ) addieren und die niedrigen Wasserzeichen von subtrahieren . Letzteres listet auch die Anzahl der freien Seiten pro Zone auf, die als Vergleich nützlich sein könnten ...Inactive(file)SReclaimable/proc/meminfo/proc/zoneinfo

Der vollständige Algorithmus ist im Patch enthalten meminfo.cund scheint relativ einfach anzupassen zu sein:

  • summiere die niedrigen Wasserzeichen über alle Zonen;
  • nimm den identifizierten freien Speicher ( MemFree);
  • subtrahieren Sie das niedrige Wasserzeichen (wir müssen vermeiden, es zu berühren, um ein Austauschen zu vermeiden);
  • Fügen Sie die Speichermenge hinzu, die wir aus dem Seitencache verwenden können (Summe von Active(file)und Inactive(file)): Dies ist die Speichermenge, die vom Seitencache verwendet wird, abzüglich der Hälfte des Seitencaches oder des niedrigen Wasserzeichens, je nachdem, welcher Wert kleiner ist.
  • Fügen Sie die Speichermenge hinzu, die wir SReclaimablenach demselben Algorithmus zurückfordern können ( ).

Wenn Sie all dies zusammenfassen, können Sie den Speicher für einen neuen Prozess verfügbar machen mit:

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 
Stephen Kitt
quelle
Ah, gut, also sollte es zumindest über dieselbe Kernelversion portierbar sein. Das ist etwas. Ich teste Ihren Vorschlag, mit 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/meminfodem ich die gleiche Nummer erhalten soll, die zweimal gedruckt wurde. Die zweite Zahl (mein Verständnis des von Ihnen vorgeschlagenen Algorithmus) ist jedoch höher als die MemAvailablein /proc/meminfo. Was mache ich falsch?
Terdon
2
/proc/zoneinfozählt Seiten, die meistens 4 KB groß sind amd64; Sie vermissen auch die zusätzliche Sicherheit, die dem Seitencache und dem wiedergewinnbaren Speicher hinzugefügt wurde. Wenn wir letzteres vereinfachen, können wir das niedrige Wasserzeichen dreimal subtrahieren, sodass m-12*low(3 × 4 KB) auf meinem System das richtige Ergebnis liefert. (Diese Vereinfachung unterschätzt den verfügbaren Speicher, wenn der Seiten-Cache oder der wiedergewinnbare Speicher kleiner als das Doppelte des niedrigen Wasserzeichens ist, aber Sie möchten in dieser Situation ohnehin nicht viel Speicher verwenden, sodass dies ein vernünftiger Kompromiss zu sein scheint.)
Stephen Kitt
1
@StephenKitt Wie würden Sie es für ältere Kernel berechnen, die weder (file)Entires noch den SReclaimableEintrag haben? Auf einer älteren Centos-Box mit Kernel v 2.6.18-348.16.1.el5xen (per uname -r) ist dies die Ausgabe, die ich erhalte: pastebin.com/iFWiM1kX . Ihre Berechnung zieht nur das MemFreeTeil
Mitch
@Mitch Ich weiß nicht, ich bin nicht sicher, ob die von Ihrem alten Kernel verfügbaren Informationen ausreichen, um den verfügbaren Speicher (vor dem Auslagern) genau zu bestimmen.
Stephen Kitt
Vielen Dank an alle, die zu diesem Thread beigetragen haben. Es ist eine großartige Referenz. Die Berechnung von MemAvailable wurde in Linux 4.5 leicht angepasst. Die neue MemAvailable-Berechnung sollte jedoch immer etwas höher sein als die alte (oder möglicherweise dieselbe), sodass die alte Berechnung in allen Fällen sicher verwendet werden kann. gitlab.com/procps-ng/procps/issues/42
sourcejedi
6

Während Stephens Antwort völlig ausreichend ist und Vorsicht geboten ist, habe ich beschlossen, die vollständige Logik einschließlich der minimalen Vergleiche aufzuschreiben. Informationen werden zuerst aus / proc / meminfo gelesen und in einer Variablen gespeichert, damit die Speicherdetails konsistent sind.

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

Das in der Variablen gespeicherte Ergebnis wird in Bytes angegeben.

Crashmaxed
quelle