Начнет ли Linux убивать мои процессы, не спрашивая меня, не хватает ли памяти?

66

Я запускал сценарий оболочки с командами для запуска нескольких ресурсоемких программ (2-5 ГБ) подряд. Когда я вернулся, чтобы проверить ход выполнения моего сценария, я с удивлением обнаружил, что некоторые из моих процессов были Killedтакими, как сообщил мне мой терминал. Несколько программ уже были успешно завершены до Killedзапуска программ, которые позже были запущены, но впоследствии все программы потерпели неудачу из-за ошибки сегментации (которая могла или не могла быть вызвана ошибкой в ​​моем коде, продолжайте читать).

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

Возможно ли, что Linux убил мои программы после того, как началось нехватка памяти? И возможно ли, что ошибки сегментации, которые я получил позже, были вызваны нехваткой памяти, доступной для запуска моих программ (вместо ошибки в моем коде)?

NeutronStar
источник
2
Когда вы выделяете память, у вас есть оператор, чтобы проверить, была ли память выделена успешно? Это должно дать понять, есть ли ошибка в вашем коде или это было связано с нехваткой памяти в системе.
unxnut

Ответы:

72

Может.

Есть два разных состояния нехватки памяти, с которыми вы можете столкнуться в Linux. То, с чем вы столкнетесь, зависит от значения sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Введение:
ядро может выполнять то, что называется «переполнение памяти». Это когда ядро ​​выделяет программам больше памяти, чем на самом деле присутствует в системе. Это делается в надежде на то, что программы на самом деле не будут использовать всю выделенную ими память, поскольку это довольно распространенное явление.

overcommit_memory = 2

Когда overcommit_memoryустановлено значение 2, ядро ​​не выполняет никакого overcommit вообще. Вместо этого, когда программе выделяется память, ей гарантирован доступ к этой памяти. Если в системе недостаточно свободной памяти для удовлетворения запроса на выделение, ядро ​​просто вернет ошибку для запроса. Программа должна изящно справиться с ситуацией. Если он не проверяет, что выделение прошло успешно, когда оно действительно не удалось, приложение часто будет сталкиваться с segfault.

В случае с segfault вы должны найти такую ​​строку в выводе dmesg:

[1962.987529] myapp[3303]: segfault at 0 ip 00400559 sp 5bc7b1b0 error 6 in myapp[400000+1000]

В at 0означает , что приложение пытались получить доступ неинициализированный указатель, который может быть результатом неудачного вызова выделения памяти (но это не единственный способ).

overcommit_memory = 0 и 1

Когда overcommit_memoryустановлено значение 0или 1, избыточная передача включена, и программам разрешается выделять больше памяти, чем реально доступно.

Однако, когда программа хочет использовать память, которая была ей выделена, но ядро ​​обнаруживает, что на самом деле у нее недостаточно памяти для ее удовлетворения, ей необходимо вернуть часть памяти. Сначала он пытается выполнить различные задачи очистки памяти, такие как очистка кэшей, но если этого недостаточно, он завершит процесс. Это прекращение выполняется OOM-Killer. OOM-Killer просматривает систему, чтобы увидеть, какие программы используют какую память, как долго они работают, кто их запускает и ряд других факторов, чтобы определить, какой из них будет убит.

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

Однако даже в этом режиме программам все равно может быть отказано в распределении запросов. Когда overcommit_memoryэто так 0, ядро ​​пытается определить, когда оно должно начать отклонять запросы на выделение. Когда он установлен на 1, я не уверен, какое определение он использует, чтобы определить, когда ему следует отклонить запрос, но он может отклонить очень большие запросы.

Вы можете увидеть, участвует ли OOM-Killer, посмотрев выходные данные dmesgи найдя такие сообщения, как:

[11686.043641] Out of memory: Kill process 2603 (flasherav) score 761 or sacrifice child
[11686.043647] Killed process 2603 (flasherav) total-vm:1498536kB, anon-rss:721784kB, file-rss:4228kB
Патрик
источник
Итак, похоже, что обе ситуации произошли со мной.
NeutronStar
@ Джошуа, я только что обновил ответ. Я забыл упомянуть, что вы все равно можете получить ошибки выделения, когда overcommit_memoryустановлено значение 0 или 2.
Патрик
Я думаю, что редактирование ссылки на Укрощение убийцы OOM в пост может быть целесообразным.
0xC0000022L
@ 0xC0000022L Спасибо, это хорошая статья (хотя и немного устаревшая). Я не хотел ничего рассказывать об управлении убийцей OOM, так как это не является частью вопроса (и это не короткая тема), и у нас здесь есть масса других вопросов именно об этом.
Патрик
1
@mikeserv Я не говорю, что поведение убийцы OOM не имеет никакого отношения к контролю над ним. Вопрос был в том, убьет ли linux его программы. Чтобы предотвратить это, прежде всего нужно убедиться, что это действительно Linux. И если overcommit_memory=2убийца OOM даже не включен, то контролировать его не имеет значения. Однако, как только мы установим, что это убийца OOM, это становится другой темой, в которой рассматриваются многие другие вопросы и ответы здесь.
Патрик
16

Правда в том, что независимо от того, как вы на это смотрите - будь то ваш процесс захлебнулся из-за системного менеджера памяти или из-за чего-то другого - это все равно ошибка. Что случилось со всеми этими данными, которые вы просто обрабатывали в памяти? Это должно было быть сохранено.

Хотя overcommit_memory=это наиболее общий способ настройки управления OOM в Linux, он также настраивается для каждого процесса, например:

echo [-+][n] >/proc/$pid/oom_adj

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

Вы можете проверить текущие настройки обработчика OOM для каждого процесса, например:

cat /proc/$pid/oom_score 

В противном случае вы можете пойти на самоубийство:

sysctl vm.panic_on_oom=1
sysctl kernel.panic=X

Это приведет к перезагрузке компьютера в случае нехватки памяти. Вы указываете Xколичество секунд, в течение которых компьютер должен останавливаться после паники ядра перед перезагрузкой. Неистовствовать.

И если по какой-то причине вы решили, что вам это нравится, сделайте это настойчивым:

echo "vm.panic_on_oom=1" >> /etc/sysctl.conf
echo "kernel.panic=X" >> /etc/sysctl.conf
mikeserv
источник
Я использую общий кластер, я уверен, что другие пользователи не оценят его перезагрузку без их согласия.
NeutronStar
3
@ Джошуа - я очень серьезно сомневаюсь, что кому-то это понравится - это даже противоречит законам робототехники Асимова. С другой стороны, как я уже говорил, вы можете настроить OOM для каждого процесса и другим способом. То есть вы можете лично сортировать данные на основе ваших собственных наборов правил для каждого процесса. Похоже, что это может быть особенно полезно в сценарии с общим кластером.
mikeserv