September 8, 2021
Алгоритм расчёта OOM Score
Алгоритм расчета уровня негодности процесса (итоговое значение будет измеряться в очках негодности (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 критической ошибкой.