Стырнечено с catap.ru
Начинаю новый цикл «про память». Первой темой будет магический OOM Killer.
OOM Killer – это способ ядра решить проблему, когда памяти недостаточно. Известно, что виртуальной памяти может быть бесконечно много (в пределах адресации), а вот физической – вполне конечное число. Иногда процессы системы съедают ее всю, и системе надо кого‑то убить, чтобы продолжить работу. Текущая реализация OOM Killer в Linux стремится выбрать наименее важный процесс. Он выбирает среди всех процессов, кроме init и kernel threads, самый негодный (badness).
Алгоритм расчета уровня негодности процесса (итоговое значение будет измеряться в очках негодности (badness ponts)):
1.
Берется размер виртуальной памяти процесса (total_vm). Это базовые очки негодности (mm/oom_kill.c:69).
2.
К текущим очкам прибавляется total_vm/2 + 1 для всех порожденных процессов (mm/oom_kill.c:85).
3.
Текущие очки делятся на int_sqrt(cpu_time), где cpu_time – это user + system время процесса сдвинутое вправо на SHIFT_HZ + 3, т.е. для HZ=1000 приблизительно будет равен значению int_sqrt((utime+stime)/10). причем если результат деления и последующего округления будет 0 – то очки не изменяются (mm/oom_kill.c:100).
4.
Текущие очки делятся на int_sqrt(int_sqrt(run_time/1024)), где run_time – время прошедшое с момента запуска процесса. Если результат 0 – то очки не изменяются (mm/oom_kill.c:100).
5.
Очки умножаются на 2, если nice процесса больше 0 (mm/oom_kill.c:118).
6.
Если процесс имеет привилегию CAP_SYS_ADMIN или CAP_SYS_RESOURCE или (e)uid в нуле, то текущие очки делятся на 4 (mm/oom_kill.c:125).
7.
Если процесс имеет привилегию CAP_SYS_RAWIO, то текущие очки делятся на 4 (mm/oom_kill.c:133).
8.
Если память процесса, для которого мы считаем очки негодности, пересекается с памятью процесса, для которого в момент выделения новой памяти произошла ошибка out of memory, тогда очки делятся на 8 (для ядер старше 2.6.28, mm/oom_kill.c:142).
9.
Набранные очки умножаются на 2oom_adj, где oom_adj – берется из /proc/$PID/oom_adj, он может принимать значения от -17 до 15. В случае значения -17 процесс не будет тронут OOM Killer (mm/oom_kill.c:150).
И самый негодный (с самыми большими очками) процесс будет убит.
Небольшие пояснения.
1. При расчете дочерних total_vm учитываются только процессы с самостоятельной виртуальной памятью. Т.е. не потоки.
2. Предполагается, что если приоритет больше нуля, то выполнение этого процесса менее критично, чем выполнение процессов с отрицательным приоритетом.
3. Предполагается, что root-процессы важнее, чем процессы непривилегированных пользователей.
4. Убийство процессов, которые осуществляют прямую работу с устройствами, может повлечь за собой нежелательные последствия.
5. OOM Killer стремится убивать более молодые процессы. Это надо, чтобы OOM Killer убил только что запущенный процесс с утечкой памяти и не тронул старые, добротные процессы, которые просто кушают много памяти ☺
6. OOM Killer стремится сохранить жизнь процесса, при выделении памяти для которого произошла ошибка out of memory, и процессам, у которых с ним есть общая память (для ядер старше 2.6.28).