Как я могу получить объем доступной памяти для разных дистрибутивов?

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) и надежно получать объем памяти, исключая подкачку, который доступен для моего программного обеспечения для использования в конкретное время? Предположительно, это то, что показано как «available» и «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. Что я делаю неправильно?
Тердон
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часть
Митч
@ Совсем не знаю, я не уверен, что информации, доступной из вашего старого ядра, достаточно для точного определения доступной памяти (до замены).
Стивен Китт
Спасибо всем, кто внес свой вклад в эту тему, это отличная ссылка. Вычисление MemAvailable было немного скорректировано в Linux 4.5. Однако новый расчет MemAvailable всегда должен быть немного выше (или может быть таким же, как) старого, поэтому во всех случаях следует безопасно использовать старый расчет. gitlab.com/procps-ng/procps/issues/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

Результат хранится в переменной в байтах.

crashmaxed
источник
В то время как этот ответ реализует вычисления в коммите 34e431b0a, ответ Стивена Китта дал более точную оценку на 2 машинах из 5, которые я тестировал. На всех 5 машинах оба ответа дали более высокие оценки, чем MemAvailable, прочитанные непосредственно из / proc / meminfo. Вероятно, более безопасный способ - получить меньшее из 2 и умножить на 0,95 или около того.
toddwz