Чи почне Linux вбивати мої процеси, не запитуючи мене, чи втрачається пам'ять?


66

У мене був запущений скрипт оболонки з командами для запуску декількох програм, що займають багато пам’яті (2-5 ГБ) «назад до спини». Коли я повернувся, щоб перевірити хід мого сценарію, я з подивом виявив, що деякі з моїх процесів були Killed, як повідомив мені мій термінал. Деякі програми вже були послідовно завершені перед програмами, які були Killedзапущені пізніше , але всі програми згодом зазнали помилки в сегментації (що може бути, а може і не бути через помилку в моєму коді, продовжуйте читати).

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

Чи можливо, що Linux вбив мої програми після того, як у неї закінчилося пам'ять? І чи можливо, що помилки сегментації, які я отримав пізніше, були через відсутність пам'яті для запуску моїх програм (замість помилки в коді)?


2
Коли ви виділяєте пам'ять, чи є у вас оператор, щоб перевірити, чи успішно було виділено пам'ять? Це має дати зрозуміти, чи є у вашому коді помилка чи це було через брак пам'яті в системі.
unxnut

Відповіді:


72

Це може.

У Linux є два різні умови пам'яті. Що ви стикаєтесь, залежить від значення sysctl vm.overcommit_memory( /proc/sys/vm/overcommit_memory)

Вступ:
Ядро може виконувати те, що називається «перевиконання пам'яті». Це коли ядро ​​виділяє програмам більше пам’яті, ніж є насправді в системі. Це робиться в надії, що програми насправді не використовуватимуть усю виділену їм пам’ять, оскільки це досить поширене явище.

overcommit_memory = 2

Коли overcommit_memoryвстановлено значення 2, ядро ​​взагалі не виконує жодних перевиконань. Замість того, коли програмі виділяється пам'ять, гарантується доступ до цієї пам'яті. Якщо в системі недостатньо вільної пам'яті, щоб задовольнити запит на розподіл, ядро ​​просто поверне помилку для запиту. Саме програма повинна витончено впоратись із ситуацією. Якщо він не перевірить, що розподіл вдалося, коли воно справді не вдалося, програма часто зустріне 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, дивлячись на вихідні дані 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

@Joshua Я щойно оновив відповідь. Я забув згадати, що ви все одно можете отримати збої в розподілі, коли overcommit_memoryвстановлено значення 0 або 2.
Патрік

Я думаю, що редагування посилання на приборкання вбивці ООМ до посади може бути доцільним.
0xC0000022L

@ 0xC0000022L Дякую, це хороша стаття (хоча трохи застаріла). Я не хотів нічого ставити з приводу контролю вбивці OOM, оскільки це не є частиною питання (і це не коротка тема), і у нас тут є ще безліч питань.
Патрік

1
@mikeserv Я не кажу, що поведінка вбивці OOM не має нічого спільного з контролем над нею. Питання полягало у тому, чи вбиватиме Linux його програми. Як запобігти цьому Linux, спочатку потрібно встановити, що це дійсно Linux. І якщо overcommit_memory=2вбивця OOM навіть не включений, тому керувати ним не має значення. Однак, як тільки ми встановимо, що саме вбивця OOM, стає іншою темою, в якій висвітлюється багато інших питань і відповідей тут.
Патрік

16

Правда полягає в тому, що незалежно від того, на який ви погляд ви дивитесь - чи ваш процес захлинувся через менеджера пам'яті системи чи через щось інше - це все- таки помилка. Що сталося з усіма тими даними, які ти тільки що обробляв у пам'яті? Це слід було зберегти.

Хоча overcommit_memory=це найзагальніший спосіб налаштування управління Linux OOM, він також регулюється за процесом, як:

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

Я використовую спільний кластер, я впевнений, що інші користувачі не оцінять його перезапуск без їхньої згоди.
NeutronStar

3
@Joshua - Я дуже серйозно сумніваюся, що хтось цього хотів би - він навіть не відповідає законам робототехніки Асімова. З іншого боку, як я вже згадую, ви можете налаштувати OOM за процесом і в інший спосіб. Що означає, що ви можете особисто триагуватись на основі власних визначених наборів правил у процесі. Така річ звучить так, що може бути особливо корисною у спільному сценарії кластера.
mikeserv
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.