Skip to content

Latest commit

 

History

History
45 lines (28 loc) · 5.71 KB

OOM killer.md

File metadata and controls

45 lines (28 loc) · 5.71 KB

OOM Killer

OOM Killer — это способ ядра решить проблему, когда памяти недостаточно. Известно, что виртуальной памяти может быть бесконечно много (в пределах адресации), а вот физической — вполне конечное число. Иногда процессы системы съедают ее всю, и системе надо кого‑то убить, чтобы продолжить работу. Текущая реализация OOM Killer в Linux стремится выбрать наименее важный процесс. Он выбирает среди всех процессов, кроме init и kernel threads, самый негодный (badness).

Алгоритм расчета

Алгоритм расчета уровня негодности процесса (итоговое значение будет измеряться в очках негодности (badness ponts)):

  • Берется размер виртуальной памяти процесса (total_vm). Это базовые очки негодности (mm/oom_kill.c:69).

  • К текущим очкам прибавляется total_vm/2 + 1 для всех порожденных процессов (mm/oom_kill.c:85).

  • Текущие очки делятся на int_sqrt(cpu_time), где cpu_time — это user + system время процесса сдвинутое вправо на SHIFT_HZ + 3, т.е. для HZ=1000 приблизительно будет равен значению int_sqrt((utime+stime)/10). причем если результат деления и последующего округления будет 0 — то очки не изменяются (mm/oom_kill.c:100).

  • Текущие очки делятся на int_sqrt(int_sqrt(run_time/1024)), где run_time — время прошедшое с момента запуска процесса. Если результат 0 — то очки не изменяются (mm/oom_kill.c:100).

  • Очки умножаются на 2, если nice процесса больше 0 (mm/oom_kill.c:118).

  • Если процесс имеет привилегию CAP_SYS_ADMIN или CAP_SYS_RESOURCE или (e)uid в нуле, то текущие очки делятся на 4 (mm/oom_kill.c:125).

  • Если процесс имеет привилегию CAP_SYS_RAWIO, то текущие очки делятся на 4 (mm/oom_kill.c:133).

  • Если память процесса, для которого мы считаем очки негодности, пересекается с памятью процесса, для которого в момент выделения новой памяти произошла ошибка out of memory, тогда очки делятся на 8 (для ядер старше 2.6.28, mm/oom_kill.c:142).

  • Набранные очки умножаются на 2oom_adj, где oom_adj — берется из /proc/$PID/oom_adj, он может принимать значения от -17 до 15. В случае значения -17 процесс не будет тронут OOM Killer (mm/oom_kill.c:150).

И самый негодный (с самыми большими очками) процесс будет убит.

Небольшие пояснения.

  • При расчете дочерних total_vm учитываются только процессы с самостоятельной виртуальной памятью. Т.е. не потоки.
  • Предполагается, что если приоритет больше нуля, то выполнение этого процесса менее критично, чем выполнение процессов с отрицательным приоритетом.
  • Предполагается, что root-процессы важнее, чем процессы непривилегированных пользователей.
  • Убийство процессов, которые осуществляют прямую работу с устройствами, может повлечь за собой нежелательные последствия.
  • OOM Killer стремится убивать более молодые процессы. Это надо, чтобы OOM Killer убил только что запущенный процесс с утечкой памяти и не тронул старые, добротные процессы, которые просто кушают много памяти ☺
  • OOM Killer стремится сохранить жизнь процесса, при выделении памяти для которого произошла ошибка out of memory, и процессам, у которых с ним есть общая память (для ядер старше 2.6.28).

Доступные пользователю настройки:

  • самый простой способ повлиять на OOM Killer — использовать vm.overcommit_memory;
  • vm.oom_dump_tasks — делать dump всех процессов за исключением kernel threads, в dump попадает pid, uid, tgid, vm size, rss, cpu и oom_adj. Имеет смысл включать только для отладки OOM Killer;
  • vm.oom_kill_allocating_task — убивать процесс, процесс которому не хватило памяти, без выбора самого плохого;
  • vm.panic_on_oom — считать запуск OOM критической ошибкой.

OOM killer