Linux out of memory

Sysadminium

В этой статье рассматривается стратегия освобождения памяти в Linux и то, как системный администратор может этим управлять.

Стратегия освобождения памяти в Linux

Из предыдущей статьи вы узнали что каждому процессу выделяется блок памяти (виртуальная память) и он эту память использует (физическая память). Суммарно физическая память состоит из оперативной памяти и подкачки (swap). Но подкачка может лишь хранить какие-то данные, которые не очень востребованы. Процессам же, чтобы избежать сильных тормозов, требуется работать с оперативной памятью.

При всём этом, суммарно, виртуальной памяти может быть выделено больше чем есть оперативной памяти. И может случится такое, что процессу нужна память, а взять её не откуда. В этом случае ядро может высвободить занятую память тремя способами:

  • сбросить, по мнению ядра, самые ненужные данные из резидентной памяти в swap;
  • сбросить некоторые файлы, которые хранятся в Page Cache, на диск;
  • запустить специальный инструмент OOM Killer, который завершит самый ненужный и занимающий больше всего памяти процесс.

Есть несколько стратегий распределения памяти. Управлять этими стратегиями можно с помощью параметра sysctlvm.overcommit_memory. Этот параметр может принимать значения 0, 1 или 2:

  • vm.overcommit_memory = 2 — сумма виртуальной память всех процессов не будет превышать физическую память. При этом, каждому отдельному процессу будет выделено не больше vm.overcommit_ratio процентов от всей памяти.
  • vm.overcommit_memory = 1 — виртуальной памяти может быть выделено больше чем есть физической. При этом, если приложение действительно попытается использовать эту память а физической памяти не хватит, то произойдет событие out of memory. По умолчанию, при событии out of memory, запустится OOM Killer и завершит какой-то процесс. При такой стратегии можно настроить еще некоторые параметры sysctl:
    • vm.panic_on_oom = 1 — при out of memory будет происходить kernel.panic вместо запуска OOM Killer;
    • kernel.panic = 10 — при kernel.panic через 10 секунд сервер пере-загрузится.

    Работа OOM Killer

    OOM Killer — это компонент ядра Linux, призванный решать проблему недостатка памяти за счет убийства одного из существующих процессов по определённому алгоритму. В случае нехватки памяти (out of memory) он убивает процесс с помощью сигнала SIGKILL и не даёт ему корректно завершиться.

    Алгоритм работы OOM Killer следующий. Все процессы, во время своей работы, накапливают специальные балы — oom_score. И при нехватке памяти OOM Killer убивает процесс с наивысшим oom_score. Посмотреть значение oom_score для процесса можно так — cat /proc//oom_score, например:

    $ cat /proc/1/oom_score 0 $ cat /proc/2383/oom_score 668

    Как рассчитывается oom_score (взято от сюда):

    • чем больше памяти занимает процесс, тем выше oom_score;
    • чем больше у процесса дочерних процессов, тем выше oom_score;
    • чем выше у процесса Nice, тем выше oom_score;
    • чем раньше создан процесс, тем ниже oom_score;
    • если процесс имеет прямой доступ к аппаратному обеспечению, то oom_score снижается;
    • если процесс имеет root привилегии, то oom_score снижается.

    Но значением oom_score можно управлять, чтобы например обезопасить некоторые процессы от OOM Killer. Для этого у процесса есть параметр oom_score_adj. Чем меньше у процесса oom_score_adj, тем меньше oom_score.

    Вы можете задать параметр oom_score_adj для служб systemd, поправив файл юнита службы. Для этого в секции [Service] укажите параметр OOMScoreAdjust со значением от — 1000 до 1000. Если указать -1000, то OOM Killer никогда не убьёт процессы данной службы. А если указать 1000, то для OOM Killer процессы этой службы превратятся в главную цель.

    Также, вы можете напрямую записать значение oom_score_adj для определённого процесса. Для этого нужно поправить файл /proc//oom_score_adj.

    $ cat /proc/2383/oom_score_adj 0 $ cat /proc/2383/oom_score 668 $ echo 20 | sudo tee /proc/2383/oom_score_adj $ cat /proc/2383/oom_score 682

    В примере видно что вначале oom_score_adj для процесса 2383 равнялся 0, а oom_score равнялся 668. Затем я поменял значение oom_score_adj на 20 и oom_score увеличился до 682.

    Итог

    Вы узнали про некоторые параметры sysctl, с помощью которых можно настроить стратегию высвобождения памяти:

    • vm.overcommit_memory — тип стратегии;
    • vm.overcommit_ratio — процент всей памяти, который можно выделить одному процессу;
    • vm.panic_on_oom — при событии out of memory выполнить kernel.panic;
    • kernel.panic — перезагрузить сервер через указанное число секунд в случае kernel.panic.

    Также вы узнали про инструмент OOM Killer. И про значения oom_score и oom_score_adj на которые полагается OOM Killer в своей работе.

    И вы узнали что ситуация нехватки памяти называется — out of memory.

    Источник

    Использование Out Of Memory Killer в Linux

    Out of Memory Killer (OOM Killer) – это механизм ядра Linux, который освобождает оперативную память при ее исчерпании за счет принудительного завершения некоторых запущенных процессов.

    При исчерпании памяти в системе, ядро Linux вызывает OEM killer, который по определенным правилам выбирает один процесс и убивает его. Освободившаяся память передается в распоряжение ядра, которое может предоставить ее другим процессам.

    Если процесс убивается OOM Killer, в логе /var/log/messages будет такая запись:

    $ cat /var/log/messages | grep «Out of»

    Out of Memory: Killed process 123 (postgres) score 904 or sacrifice child

    OOM killer убивает процессы сигналом SIGKILL, не предоставляя им возможность корректно завершить свое выполнение (сохранить данные, вызвать другие процессы). Поэтому результат работы OOM killer часто приводит к тяжелым последствиям.

    Частое появление OOM killer говорит о нестабильности работы системы и требует от администратора внимательного анализа причин возникновения событий исчерпания памяти.

    Чтобы завершить процесс, Linux вызывает функцию out_of_memory. В функции out_of_memory вызывается функция select_bad_process, которая позволяет выбрать процесс для завершения. Все запущенные процесс оцениваются с помощью функции badness. Badness выбирает процесс по правилам, основанным на вычисленной репутацим каждого процесса (oom_score).

    Вы можете вывести репутацию процесса по его PID (например, для ID процесса 1764):

    получить рейтинг процесса oom_score в linux

    Чем выше репутация процесса, тем больше вероятность того, что именно его завершит OOM Killer.

    Вы можете отключить OOM Killer в Linux (не рекомендуется в большинстве случаев):

    $ sudo cat /proc/sys/vm/panic_on_oom

    По умолчанию тут указан 0. Это значит, что OOM Killer включен.

    $ sudo echo 1 > /proc/sys/vm/panic_on_oom

    Если вы не хотите отключать OOM Killer, но хотите гарантировать, что определенный процесс никогда не будет принудительно завершен, нужно увеличить его репутацию.

    Выведите текущую репутацию процесса:

    Можно увеличить, или уменьшить репутацию процесса, добавив в файл oom_adj значение от -16 до +15.

    $ sudo echo -5 > /proc/1764/oom_adj
    $ cat /proc/1764/oom_score

    увеличить oom_score процесса linux

    Если нужно совсем отключить OOM Killer для процесса, нужно указать в oom_adj значение -17.

    $ sudo echo -17 > /proc/1764/oom_adj
    $ cat /proc/1764/oom_score

    Однако нужно понимать, что при перезапуске процесса, его PID изменится. И эта репутация будет переназначена другому процессу с таким же PID.

    Можно динамически определять PID процесса и уменьшать его репутацию:

    $ pgrep -f «/usr/sbin/sshd» | while read PID; do echo -17 > /proc/$PID/oom_adj; done

    Но гораздо удобнее задать репутацию в файле сервиса юнита службы systemd:

    [Service] OOMScoreAdjust=-500

    Источник

    Читайте также:  Using cmake on linux
Оцените статью
Adblock
detector