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

В этой статье рассматривается стратегия освобождения памяти в 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 секунд сервер пере-загрузится.
  • vm.overcommit_memory = 0 — такая настройка используется по умолчанию. При этом ядро, с помощью специальных алгоритмов, само решает когда и сколько выделять памяти процессам.




Работа OOM Killer




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




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






2022-10-29T17:36:19
Администрирование Linux