Як я можу отримати кількість доступної пам'яті портативно в дистрибутивах?


12

Стандартні файли / засоби, що повідомляють про пам'ять, мають різні формати в різних дистрибутивах Linux. Наприклад, на Arch і Ubuntu.

  • Арк

    $ 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
    

Отже, як я можу портативно (лише через дистрибутиви Linux) і надійно отримати об'єм пам'яті (за винятком свопу), який доступний для мого програмного забезпечення у певний час? Імовірно, це те, що показано як "доступно" та "MemAvailable" на виході freeта cat /proc/meminfoв Arch, але як я можу отримати те саме в Ubuntu або іншому дистрибутиві?

Відповіді:


18

MemAvailableвходить /proc/meminfoз версії 3.14 ядра; вона була додана комітом 34e431b0a . Це визначальний коефіцієнт у виведених вами варіаціях. Повідомлення фіксації вказує, як оцінити доступну пам'ять без MemAvailable:

В даний час обсяг пам'яті, доступний для нової робочої навантаження, не висуваючи систему в обмін, може бути оцінена MemFree, Active(file), Inactive(file), і SReclaimable, а також «низький» водяні знаки з /proc/zoneinfo.

Низькі водяні знаки - це рівень, під яким система буде змінюватися. Таким чином , в разі відсутності MemAvailableви можете принаймні додати до значень , зазначених для MemFree, Active(file), Inactive(file)і SReclaimable( в залежності від того, присутні в /proc/meminfo), і віднімати низькі водяні знаки з /proc/zoneinfo. Останній також перелічує кількість вільних сторінок на зону, які можуть бути корисні для порівняння ...

Повний алгоритм наведено в патчі meminfo.cі, здається, досить легко адаптується:

  • підсумовуйте низькі водяні знаки у всіх зонах;
  • взяти ідентифіковану вільну пам'ять ( MemFree);
  • відняти низький водяний знак (нам потрібно уникати дотику, щоб уникнути заміни);
  • додайте об'єм пам'яті, який ми можемо використати з кешу сторінки (сума Active(file)та Inactive(file)): це об'єм пам'яті, який використовується кеш-сторінкою, мінус або половина кеш-сторінки, або низький водяний знак, залежно від того, що менше;
  • додати об'єм пам'яті, яку ми можемо повернути ( SReclaimable), дотримуючись того ж алгоритму.

Отже, склавши все це разом, ви можете отримати доступну пам'ять для нового процесу за допомогою:

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 

Добре, так що принаймні воно повинно бути портативним у тій же версії ядра. Це щось. Я тестую вашу пропозицію, з 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/meminfoякою слід дати мені однакову кількість, надруковану двічі. Однак друге число (наскільки я розумію запропонований вами алгоритм) вище, ніж MemAvailableпоказано в /proc/meminfo. Що я роблю неправильно?
terdon

2
/proc/zoneinfoпідраховує сторінки, розміром яких є переважно 4 КБ amd64; вам також не вистачає додаткової безпеки, доданої до кешу сторінок та пам'яті, що відновлюється. Спростивши останнє, ми можемо відняти низький водяний знак три рази, тому m-12*low(3 × 4 КБ) дає правильний результат у моїй системі. (Це спрощення недооцінює наявну пам'ять, якщо кеш-пам'ять сторінки або пам'ять, що відновлюються, менше, ніж удвічі менший водяний знак, але все одно ви не хочете використовувати багато пам'яті в цій ситуації, так що це здається розумним компромісом.)
Стівен Кітт

1
@StephenKitt як би ви вирішили обчислити його для старих ядер, у яких немає ні (file)ентерів, ні SReclaimableзапису? У старій вікні centos з ядром v 2.6.18-348.16.1.el5xen (per uname -r) це результат, який я отримую: pastebin.com/iFWiM1kX . Ваш розрахунок тягне лише за собою MemFreeчастину
Мітч

@Mitch Я не знаю, я не впевнений, що інформації, доступної для вашого старого ядра, достатньо, щоб точно визначити наявну пам'ять (перед своєю заміною).
Стівен Кітт

Дякуємо всім, хто сприяв цій темі, це чудова довідка. Розрахунок MemAvailable був трохи скорегований у Linux 4.5. Однак новий обчислення MemAvailable завжди повинен бути трохи більшим, ніж (а може бути, таким же, як і старий), тому слід використовувати безпеку для використання у всіх випадках. gitlab.com/procps-ng/procps/isissue/42
sourcejedi

7

Хоча відповідь Стівена цілком достатня і помиляється на стороні обережності, я вирішив написати повну логіку, включаючи мінімальні порівняння. Інформація спочатку зчитується з / proc / meminfo та зберігається у змінній, щоб деталі пам'яті були узгодженими.

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

Результат, що зберігається в змінній, знаходиться в байтах


Хоча ця відповідь реалізує обчислення в команді 34e431b0a, відповідь Стівена Кітта дав більш точну оцінку на 2 машинах з 5, які я перевірив. На всіх 5 машинах обидві відповіді дали більші оцінки, ніж MemAvailable, прочитані безпосередньо з / proc / meminfo. Ймовірно, більш безпечним є спосіб отримати менший між двома і помножити на 0,95 або близько того.
toddwz
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.