Jak uzyskać przenośną ilość dostępnej pamięci między dystrybucjami?


12

Standardowe pliki / narzędzia zgłaszające pamięć wydają się mieć różne formaty w różnych dystrybucjach systemu Linux. Na przykład w Arch i Ubuntu.

  • Łuk

    $ 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
    

Jak mogę przenośnie (tylko w różnych dystrybucjach Linuksa) i niezawodnie uzyskać ilość pamięci - z wyjątkiem wymiany - dostępnej dla mojego oprogramowania w określonym czasie? Prawdopodobnie to jest pokazywane jako „dostępne” i „MemAvailable” na wyjściu freeiw cat /proc/meminfoArch, ale jak mogę uzyskać to samo w Ubuntu lub innej dystrybucji?

Odpowiedzi:


18

MemAvailablejest zawarty w /proc/meminfowersji 3.14 jądra; został dodany przez commit 34e431b0a . To czynnik decydujący o wyświetlanych wariantach wyjściowych. Komunikat zatwierdzenia wskazuje, jak oszacować dostępną pamięć bez MemAvailable:

Obecnie ilość pamięci, która jest dostępna dla nowego nakładu pracy, bez pchania system do wymiany, można oszacować MemFree, Active(file), Inactive(file), i SReclaimable, a także znaki wodne „Low” z /proc/zoneinfo.

Niskie znaki wodne to poziom, poniżej którego system będzie zamieniał. Tak więc w przypadku braku MemAvailablemożna przynajmniej sumować wartości podane dla MemFree, Active(file), Inactive(file)oraz SReclaimable(w zależności od tego są obecne w /proc/meminfo) i odjąć od niskich znaków wodnych /proc/zoneinfo. Ta ostatnia zawiera również liczbę bezpłatnych stron na strefę, które mogą być przydatne jako porównanie ...

Kompletny algorytm jest podany w łatce meminfo.ci wydaje się dość łatwy do dostosowania:

  • zsumuj niskie znaki wodne we wszystkich strefach;
  • weź zidentyfikowaną wolną pamięć ( MemFree);
  • odejmij niski znak wodny (musimy unikać jego dotykania, aby uniknąć zamiany);
  • dodaj ilość pamięci, którą możemy użyć z pamięci podręcznej strony (suma Active(file)i Inactive(file)): jest to ilość pamięci używanej przez pamięć podręczną strony, pomniejszona o połowę pamięci podręcznej strony lub niski znak wodny, w zależności od tego, która wartość jest mniejsza;
  • dodaj ilość pamięci, którą możemy odzyskać ( SReclaimable), postępując zgodnie z tym samym algorytmem.

Podsumowując, możesz uzyskać dostępną pamięć dla nowego procesu dzięki:

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 

Ach, dobrze, więc przynajmniej powinien być przenośny w tej samej wersji jądra. To jest coś. Testuję twoją sugestię, 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/meminfoktóra powinna dać mi ten sam numer wydrukowany dwukrotnie. Jednak druga liczba (moje rozumienie algorytmu, który sugerujesz) jest wyższa niż MemAvailablepokazana w /proc/meminfo. Co ja robię źle?
terdon

2
/proc/zoneinfozlicza strony, które mają rozmiar głównie 4KB amd64; brakuje Ci również dodatkowego bezpieczeństwa dodanego do pamięci podręcznej strony i pamięci, którą można odzyskać. Upraszczając to drugie, możemy trzy razy odjąć niski znak wodny, więc m-12*low(3 × 4KB) daje prawidłowy wynik w moim systemie. (To uproszczenie nie docenia dostępnej pamięci, jeśli pamięć podręczna strony lub pamięć do odzyskania jest mniejsza niż dwukrotność niskiego znaku wodnego, ale i tak nie chcesz używać dużej ilości pamięci w tej sytuacji, więc wydaje się to rozsądnym kompromisem.)
Stephen Kitt,

1
@StephenKitt, jak byś wyliczył to dla starszych jąder, które nie mają ani (file)wpisu, ani SReclaimablewpisu? Na starszym pudełku Centos z jądrem w wersji 2.6.18-348.16.1.el5xen (per uname -r) jest to wyjście, które otrzymuję: pastebin.com/iFWiM1kX . Twoje obliczenia przyciągają tylko MemFreeczęść
Mitch

@Mitch Nie wiem, nie jestem pewien, czy informacje dostępne ze starego jądra są wystarczające do dokładnego określenia dostępnej pamięci (przed zamianą).
Stephen Kitt,

Dzięki wszystkim, którzy przyczynili się do tego wątku, jest to świetna referencja. Obliczenia MemAvailable zostały nieznacznie dostosowane w Linuksie 4.5. Jednak nowe obliczenia MemAvailable powinny zawsze być nieco wyższe niż (lub może być takie same) jak stare, więc we wszystkich przypadkach powinno być bezpieczne korzystanie ze starego obliczenia. gitlab.com/procps-ng/procps/issues/42
sourcejedi

7

Chociaż odpowiedź Stephena jest całkowicie wystarczająca i popełniła błąd po stronie ostrożności, postanowiłem napisać pełną logikę, w tym minimalne porównania. Informacje są najpierw odczytywane z / proc / meminfo i przechowywane w zmiennej, dzięki czemu szczegóły pamięci są spójne.

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

Wynik przechowywany w zmiennej jest w bajtach.


Podczas gdy ta odpowiedź implementuje obliczenia w zatwierdzeniu 34e431b0a, odpowiedź Stephena Kitta zapewniła dokładniejsze oszacowanie na 2 z 5 testowanych przeze mnie maszyn. Na wszystkich 5 maszynach obie odpowiedzi dały większe oszacowania niż MemAvailable odczytane bezpośrednio z / proc / meminfo. Prawdopodobnie bezpieczniejszym sposobem jest uzyskanie wartości mniejszej między 2 i pomnożenie przez około 0,95.
toddwz
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.