- -bash: fork: Невозможно выделить память
- 4 ответа
- Cannot allocate memory
- fork-bomb
- fork: Cannot allocate memory
- Redis: fork — Cannot allocate memory, Linux, виртуальная память и vm.overcommit_memory
- Почему оверкоммит вреден
- Redis persistance
- Redis save, SAVE и BGSAVE
- Redis ф ункции rdbSave() и rdbSaveBackground()
- fork() vs fork() vs clone()
- Причины Redis — fork: Cannot allocate memory
- Значения overcommit_memory
- Знаменитый «Эвристический алгоритм» (Heuristic Overcommit handling)
- Проверка vm.overcommit_memory
-bash: fork: Невозможно выделить память
Когда я запускаю любую команду в оболочке bash, она возвращает:
Затем я попытался отладить утечки памяти с помощью команды ps . Возвращает:
Как отлаживать? В чем основная проблема?
4 ответа
Я также столкнулся с этой проблемой с моим рабочим столом Ubuntu 14.04.
Даже эти основные команды показали, что невозможно выделить память. В ходе расследования выяснилось, что система использует всю память для кэширования и не освобождает память. Это называется Cache Ballooning и решается путем очистки кеша.
Сначала вы можете проверить использование системной памяти, чтобы увидеть, достаточно ли свободной памяти.
Если нет, то в моем случае проверьте свой ulimit, набрав ulimit -a , чтобы убедиться, что вы достигли предела максимального количества открытых файлов (в основном вызванного некоторыми определенными процессами, которые занимают много файловых дескрипторов). В этом случае настройка ulimit решит вашу проблему.
У меня такая же проблема. В моем случае, узнав о деталях памяти с помощью « proc / meminfo », я обнаружил идентификаторы, что они использовали много ресурсов ЦП и памяти с « TOP ». После этого я проверил, как долго они работают с » ps -o etime = -p» PID «. Msgstr «Затем я убиваю PID с помощью» kill -9 PID «.
В моем случае ОС работала без PID вместо памяти, сообщение об ошибке было то же самое.
Значение по умолчанию для максимального числа PID равно 32768, чтобы просмотреть значение, запустите
Чтобы изменить максимальный номер pid, запустите
В моем сценарии основной причиной было то, что один процесс Java порождал 18k + потоков (в ядре Linux, поток по сути является процессом), чтобы выяснить количество потоков каждого процесса, запустите
Источник
Cannot allocate memory
Есть маленький сервачек на Атоме с 1G оперативки. В какой-то момент начинает сильно тормозить и на любую консольную команду получаю «Cannot allocate memory». Ни ps ни top не вызвать и не посмотреть какой процесс отожрал всю память. Вопрос как этого избежать? Как настроить систему что бы она убивала процесс который угрожает работоспособности системы исчерпыванием памяти или CPU или обращением к диску?
Запусти top заранее. А вообще, должен бы OOM отработать.
Что такое поиск в гугле?
fork-bomb
Добавь свопа и отключи оверкоммит.
Судя по строчкам в syslog «Out of memory: Kill process» OOM срабатывает но сервак к этому моменту уже даже на ping не отвечает не говоря уже о ssh.
сделай небольшой своп, хотя-бы на 512Мб.
Судя по строчкам в syslog «Out of memory: Kill process»
там же оно пишет КАКОЙ процесс.
А как отключить оверкоммит для конкретного процесса?
Процессы всегда разные.
Для конкретного — никак, это общесистемная настройка. Для конкретного процесса можно попробовать ulimit на память.
Вроде ж OOM не сразу по окончании свободной памяти начинает убивать процессы, а спустя какое-то время, около получаса, пока он соберет статистику по процессам? Или нет? // просто мимо проходил, вспомнил заявление одного анонимуса
Пока я не отключил своп, OOM кил вообще не было, сервак просто умирал.
overcommit это стратегия ядра, она для процессов не имеет смысла.
ещё раз: своп сделай. Тогда ООМ будет лучше работать, а не пальцем в небо.
ЗЫЖ возможно overcommit не нужно выключать, а может и нужно. Сначала разберись в проблеме, а потом всё остальное.
а спустя какое-то время, около получаса, пока он соберет статистику по процессам? Или нет?
Это мешает тебе поставить ulimit или отключить overcommit?
Можешь еще залогиниться по ssh и запустить там в цикле ps — может, успеешь увидеть, какой процесс резко растолстел. Хотя это может быть не утечка памяти, а форк-бомба.
Вообще оч. странно что простой процесс от простого пользователя может уложить систему просто исчерпанием памяти.Как сделать работе OOM более жесткой?
Ок,а что у линукс нет защиты от форк-бомб?
Что нужно ограничить ulimit? Какие надо вставить параметры и как их рассчитать?
Есть, но нетривиальная.
Впервые такое слышу. Да и что система будет в эти полчаса делать, если резерва памяти уже нет? Какую память выделять процессам?
Не знаю, мопед не мой 🙂
А что на сервере крутится? Оно и жрёт память, что ещё )
В какой-то момент начинает сильно тормозить и на любую консольную команду получаю «Cannot allocate memory».
На сколько быстро это происходит ? Можно попробовать алерт какой-нибудь настроить на некий оставшийся объём и успеть зайти по алерту.
Ок,а что у линукс нет защиты от форк-бомб?
Не надо запускать всё подряд из-под root, а для обычных юзеров можно настроить лимиты.
Это не важно что крутится, меня возмущает что простой пользователь может запустить кривое приложение и уложить сервак. Вера в Линукс тает.
Почить моментально. Как форк-бомб
Пока я не отключил своп, OOM кил вообще не было, сервак просто умирал.
он не «умирал», а начинал дико тормозить. Наверное своп очень большой был, ну и пока оно всё не заполнится, ООМ не почешется. Тут либо своп надо делать маленький, либо подождать. Оно работает, только дико тормозит. Но обычно можно дождаться ответа.
Ок,а что у линукс нет защиты от форк-бомб?
тебе обязательно давать шелл потенциальны врагам?
Как то тяжело начальству объяснить что сервак не умер а дико тормозит. И ответа можно ждать минут 20-30, а это не приемлемо. А зачем делать своп? если нет свопа ООМ быстрее отработает. Если процесс начал жрать память то надежда слабая что он остановится пока она вся не кончится, его как можно быстрее нужно прибить как бешенную собаку.
Линукс тебе лишние гигабайты памяти из ниоткуда не нарисует, впрочем как и другие ОС
Если процесс начал жрать память то надежда слабая что он остановится
пока она вся не кончится, его как можно быстрее нужно прибить как
бешенную собаку.
Проблема ещё в том, что процесс может быть не тот. ООМ killer убивает, исходя из активности процесса, а не объёма памяти. Если тот, кто съедает память, делает это неторопливо, OOM killer может и не обратить внимание на него.
Как то тяжело начальству объяснить что сервак не умер а дико тормозит.
Да, тяжело, особенно, если пять минут назад узнал про лимиты и про то, что их настраивать нужно, да ещё веру в Линукс потерял 🙂
Если процесс начал жрать память то надежда слабая что он остановится пока она вся не кончится
Это очень сильно зависит от процесса. Если у процесса медленно потекла память, но при этом он работает, то можно просто отслеживать уровень использования swap’а и принимать меры. При этом, если процесс жрёт и память и процессорное время, то не факт, что OOM-killer выберет именно его, а не какой-нибудь другой, нормальный процесс, который не нужно убивать.
В отсутствии лишней памяти в swap вытесняются не особо нужные процессы, например, udevd. Кроме того без swap трудно отключить overcommit памяти.
И ваш случай больше похоже на fork-bomb, а не на утечку памяти.
А то, что система перестаёт отвечать на ping вобще подозрительно.
Как то тяжело начальству объяснить что сервак не умер а дико тормозит.
дык это для поиска причины нужно. А начальству потом отрапортуешь: УМВР. Ну или «для приложения XYZ нужно добавить N памяти».
А зачем делать своп? если нет свопа ООМ быстрее отработает. Если процесс начал жрать память то надежда слабая что он остановится пока она вся не кончится, его как можно быстрее нужно прибить как бешенную собаку.
если не делать своп, то у ООМ нет времени набрать статистику, и выяснить, КТО жрёт память. Вот он и рубит пальцем в небо.
Если тот, кто съедает память, делает это неторопливо, OOM killer может и не обратить внимание на него.
тогда это должен смотреть администратор. Если какое-то приложение пожрало 70% RES, то конец немного предсказуем, и тут уже ничего не поможет, кроме покупки RAM(да и то, если приложение нормально написано. Возможно этот быдлокод просто течёт).
тогда это должен смотреть администратор.
Так вот и речь у ТС о том, как поймать вредителя. Кстати, можно попробовать поставить collectd и перечислить подозрительные процессы в Plugin processes. Кажется, там занимаемая память тоже пишется.
Источник
fork: Cannot allocate memory
Что творится с серваком? Несколько лет работал а тут такое. Раза с 20 зашел по ssh на все команды fork: Cannot allocate memory, но если долго пытаться то команды выполняются. Свободной памяти много. В чем проблема? Может быть в физическом повреждении RAM?
OS, ядро, dmesg, сколько процессов ? Может баг в ядре который ребутом полечится
А процессов сколько?
Debian 7.11 3.2.0-4-amd64 процессов 146 в dmesg чисто, ребут был.
/proc/meminfo и /proc/sys/vm/overcommit_memory покажи
3.2.0 — както стремно (уже 84 багфикса было для 3.2 ветки).
А что в /proc/slabinfo ? И сколько всего потоков ?
у тебя что-то из лимитных вещей закончилось. Возможно дескрипторы или что-то подобное.
Окей, а теперь покажи пожалуйста ulimit -a
Хм, тоже вроде никакого криминала(у меня например, некоторые параметры даже ниже по дефолту). Ну и наконец выхлоп ps aux на какой-нибудь pastebin бы не помешал
Update: вот тут чуть подробнее расписали возможные проблемы
Ищите процесс (процессы) которые запросили большое количество RAM (можно в top Shift+M и смотреть у кого большой VIRT)
Вообще не интересно самый жирный это
И кто у нас 21776? Чинится ли всё, если его прибить?
Насколько я понял 21776 процесс запросил 36G RAM
Да действительно прибил 21776 и все наладилось. Но вот что странно запросил он 35.0g а использовал всего 2.5g. Притом своп пустой на запросы памяти сыпется Cannot allocate memory. Почему?
Есть подозрение что дело в overcommit и бажном процессе, который сделал malloc на overдохрена памяти
top — 21:32:03 up 5:36, 2 users, load average: 0.14, 0.19, 0.18
Tasks: 138 total, 1 running, 137 sleeping, 0 stopped, 0 zombie
%Cpu(s): 13.5 us, 0.8 sy, 0.0 ni, 85.3 id, 0.2 wa, 0.0 hi, 0.1 si, 0.0 st
KiB Mem: 32878740 total, 10601464 used, 22277276 free, 62572 buffers
KiB Swap: 16768892 total, 0 used, 16768892 free, 6246996 cached
Это ты шифруешься так, что ли? Я понимаю там логины пользователей еще скрывать, но что у тебя такого сверхсекретного в именах процессов? 🙂
И еще, ты так и не ответил что именно за процесс был под pid 21776.
Логично. Процесс кривой но нужный, раньше столько МЕМа не заказывал.
Это что бы холивар не разводить. Java это была java :)))
Не дай бохъ узнают, шо java (подкодит по кол-ву символов) крутит. 😉
Вариантов тут немного: либо фиксить поведение процесса(патчить, писать багрепорты и/или накатывать новую версию), либо переключать overcommit в режим 2.
ОСТОРОЖНО: неправильные настройки overcommit могут к чертям сломать тебе систему, пока не откатишь в зад. Например, у меня при дефолтных 50% overcommit_ratio на десктопе с 4G RAM напрочь отказывались запускаться ЛЮБЫЕ приложения на java(даже hello world).
Update: гы, как в воду глядел, начал писать коммент до того как увидел инфу про java 🙂
Крути настройки GC в java, ну или overcommit, но осторожно и желательно с локальным доступом(хотя SSH по идее прибивается OOM-Killer-ом в сааамую последнюю очередь, так что. )
Источник
Redis: fork — Cannot allocate memory, Linux, виртуальная память и vm.overcommit_memory
Cейчас настраиваю Redis как кеширующий сервис приложения, и среди прочего встал вопрос — надо ли включать vm.overcommit_memory в 1, или нет?
Вопрос достаточно старый, см. История, но вот докопаться до сути, упорядочить и привести в читабельный вид удалось только сейчас.
Проблема заключается в том, что официальная документация и практически все гайды/HowTo-шки по Redis достаточно легкомысленно предлагают «волшебную пилюлю» в виде безусловного разрешения overcommit_memory , особенно в случае ошибки вида «fork — Cannot allocate memory«.
Попробуем разобраться — что overcommit_memory даёт, когда она используется, и нужна ли она в нашем случае.
Почему оверкоммит вреден
Смотрите полный пост тут>>>.
Когда операционная система, такая как Linux, выделяет память процессу из юзерспейса (запрошенного с помощью brk() или mmap() ) — между виртуальными и реальными областями памяти нет никакой связи до тех пор, пока процесс не попробует обратиться к этой памяти — после этого ядро и MMU выполнят маппинг виртуального адреса к физическому.
Overcommit означает выделение виртуальной памяти больше, чем доступно физической, т.е. нет никакой гарантии, что при необходимости, когда процесс начнёт активно использовать выделенную ему виртуальную память — ядро сможет сформировать связь между всей выделенной виртуальной памятью и физической.
Если использовать аналогии, то это как использовать кредитную карту и не следить за расходами: система просто выделяет нам бесконечное количество виртуальной памяти, пока не приходят коллекторы — т.е, пока программа не начинает использовать ранее незатронутую память, для которой потребуется физическая память — а ядро не может её выделить, потому что она закончилась.
Redis persistance
Redis использует два механизма обеспечения целостности данных — RDB (point-in-time snapshot), который выполняет копирование существующих данных из памяти на диск, и AOF, при котором записываются все операции, выполненные сервером во время работы. См. Redis Persistence.
overcommit_memory играет роль при выполнении операций созданий снапшотов данных из памяти на диск, а конкретно — при вызовах BGSAVE и BGREWRITEAOF .
Ниже мы будем рассматривать процесс именно BGSAVE , при котором Redis порождает дочерний процесс, который и выполняет копирование базы данных Redis из памяти на диск, т.е. создаёт snapshot данных.
Redis save, SAVE и BGSAVE
Немного путаницы может внести сам Redis: в файле настроек параметр save отвечает как раз за создание резервной копии из дочернего процесса, т.е. BGSAVE .
При этом, у Redis есть команда SAVE , которая так же создаёт дамп данных — но работает она иначе:
- SAVE является синхронной командой, и выполняет блокирование операций записи в память на время, пока создаётся копия данных
- BGSAVE , в свою очередь, выполняет асинхронное копирование, т.е. запускается параллельно основному процесу Redis, и не влияет на его работу и подключенных к нему клиентов, а потому является предпочтительным способом создания копии данных
Однако в случае, если BGSAVE не может быть выполнена, например из-за ошибки «Can’t save in background: fork: Cannot allocate memory» — можно вызвать SAVE .
Что бы проверить это — используем strace .
Создаём тестовый конфиг redis-testing.conf :
Запускаем strace и redis-server с этим конфигом:
strace пишет данные в файл redis-trace.log, который и будем проверять на предмет используемых системных вызовов, которые выполняет redis-server при операциях SAVE и BGSAVE :
Тут через grep -v убираем «мусорные» вызовы, которые нас сейчас не интересуют. Можно было бы через -e trace= выбрать только нужные — но пока не ясно, что именно будет интересно.
В файле Redis настроек мы указали port 777 и save 1 1 , т.е. — создавать копию базы из памяти на диск каждую секунду если изменился как минимум 1 ключ.
Добавляем ключ в базу:
$ redis-cli -p 7777 set test test
И проверяем лог strace :
Вот и вызов clone() (почему clone() , а не fork() — будет чуть ниже, в fork() vs fork() vs clone()), который и порождает дочерний процесс, который выполняет создание дампа базы.
Теперь — выполним команду SAVE :
$ redis-cli -p 7777 save
И проверяем лог:
clone() нет — дамп базы был создан напрямую основным процессом Redis-сервера, и сохранён в файл dump.rdb — строка rename(«temp-1652.rdb», «dump.rdb»). в выводе strace (мы сейчас увидим — откуда взялось имя temp-1652.rdb).
$ redis-cli -p 7777 bgsave
И снова наш clone() , который породил дочерний процесс с PID 1879:
Redis ф ункции rdbSave() и rdbSaveBackground()
Собственно RDB-дамп выполняется единственной функцией Redis — rdbSave() :
Которая вызывается при прямом вызове redis-cli -p 7777 SAVE .
А вот и имя файла temp-1652.rdb из результатов strace чуть выше:
Где 1652 — PID процесса Redis-сервера.
В свою очередь при BGSAVE вызывается функция rdbSaveBackground() :
Которая как раз и порождает новый процесс:
В котором и вызывается rdbSave() :
fork() vs fork() vs clone()
Вернёмся к вопросу — почему в выводе strace мы видим не fork() , а clone() , ведь функция rdbSaveBackground() вызывает именно fork() ?
А потому, что fork() != fork() :
- есть fork() , который является системным вызовом Linux-ядра
- есть fork() , который является функцией библиотеки glibc , которая является обёрткой над системным вызовом clone()
Тут может пригодится apropos :
/Temp/redis] [unstable*] $ apropos fork
Далее, открываем man 2 fork :
/Temp/redis] [unstable*] $ man 2 fork | grep -A 5 NOTES
rather than invoking the kernel’s fork() system call, the glibc fork() wrapper […] invokes clone(2)
Следовательно, когда вызывается fork() из rdbSaveBackground() — он вызывает не системный вызов fork(2) , а функцию fork(3p) из библиотеки glibc , которая переадресовывается в __libc_fork() :
А в самом __libc_fork() — «магия» происходит в макросе arch_fork() :
/Temp/glibc] [master*] $ grep -r arch_fork .
arch_fork() описан в файле sysdeps/unix/sysv/linux/arch-fork.h , и он и как раз и вызывает clone() :
Который мы и видим в выводе strace .
Что бы убедиться, что мы в самом деле используем glibc fork() , а не системный вызов Linux — используем такой пример из документации GNU:
В pid = fork() вызываем fork() аналогично тому, как это происходит в rdbSaveBackground() , и запускаем с ltrace для отслеживания вызова библиотечных функций (в отличии от strace для системных вызовов):
С помощью lsof проверяем открытые нашим процессом файлы:
/Temp/glibc] [master*] $ lsof -p 5531
Либо с помощью ldd проверим используемые библиотеки:
/Temp/glibc] [master*] $ ldd test_fork_lib
libc-2.29.so входит в пакет glibc :
/Temp/glibc] [master*] $ pacman -Ql glibc | grep libc-2.29.so
Другой вариант — с помощью objdump проверить саму библиотеку:
/Temp/linux] [master*] $ objdump -T /usr/lib/libc.so.6 | grep fork
Причины Redis — fork: Cannot allocate memory
При создании копии данных Redis полагается на механизм Copy-on-Write.
Redis порождает новый процесс через вызов fork() , который является полной копией родительского процесса, и в теории — должен занимать столько же места, как и родительский процесс, т.е. процесс самого Redis-сервера. И хотя новый процесс может и, как правило, занимает значительно меньше места благодаря механизму ядра copy-on-write, Linux всё-равно постарается выделить ему столько же виртуальной памяти, сколько выделено под родительский процесс, т.к. нельзя предстаказать — сколько страниц памяти изменятся в процессе выполнения копирования.
Таким образом, если у системы недостаточно свободной памяти, а overcommit_memory установлен в 0 — то ядро откажет в выделении памяти под новый процесс, и fork() завершится с ошибкой.
Значения overcommit_memory
vm.overcommit_memory может иметь одно из трёх значений:
- 0: ядро может выделить больше виртуальной памяти, чем доступно реально, но при этом полагается на «эвристический алгоритм» (heuristic overcommit handling) при принятии решения о выделении или об отказе
- 1: ядро всегда будет выполнять overcommit, что увеличивает вероятность ошибок Out of memory, но должно позитивно влиять на производительность процессов, активно использующих память
- 2: ядро не будет выделять памяти больше, чем определено в overcommit_ratio или overcommit_kbytes
Знаменитый «Эвристический алгоритм» (Heuristic Overcommit handling)
В большинстве документации/гайдов/вопросов на StackOverflow упоминается только этот самый «эвристический алгоритм», но что за алгоритм — удалось найти не сразу.
Собственно, проверка выделения памяти выполняется во вспомогательной функции __vm_enough_memory() из модуля memory management из файла mm/util.c , которой передаётся количество запрашиваемых для выделения страниц памяти (long pages), и которая выполняет:
- если overcommit_memory == 1 ( if (sysctl_overcommit_memory == OVERCOMMIT_ALWAYS) ):
- возвращем 0, и разрешаем выделение
- если overcommit_memory == 0 ( if (sysctl_overcommit_memory == OVERCOMMIT_GUESS) , а sysctl_overcommit_memory по умолчанию задаётся в OVERCOMMIT_GUESS, а OVERCOMMIT_GUESS задаётся в 0 в файле linux/mman.h ):
- считается количество свободных страниц памяти, которое заносится в переменную free:
free = global_zone_page_state(NR_FREE_PAGES) - считается количество file-backed (см. File-backed and Swap, Memory-mapped file) страниц памяти, т.е. те траницы памяти, которые могут быть особождены
free += global_node_page_state(NR_FILE_PAGES) - вычитается кол-во разделяемой памяти (см. Shared Memory, Shared memory)
free -= global_node_page_state(NR_SHMEM) - добавляются swap-страницы
free += get_nr_swap_pages() - добавляет SReclaimable (см. man 5 procSReclaimable)
free += global_node_page_state(NR_SLAB_RECLAIMABLE) - и добавляет KReclaimable (см. man 5 procKReclaimable)
free += global_node_page_state(NR_KERNEL_MISC_RECLAIMABLE) - вычитает минимально зарезервированное количество страниц (см. calculate_totalreserve_pages() и An enhancement of OVERCOMMIT_GUESS)
free -= totalreserve_pages - вычитает память, зарезервиванную для root (см. init_admin_reserve() )
free -= sysctl_admin_reserve_kbytes - и последним шагом проверяется значение доступной памяти, и запрошенной — если free (в которой содержится результат всех предыдущих вычислений) больше pages (кол-во требуемых страниц) — то возвращается 0, и память выделяется:
if (free > pages) return 0;
- считается количество свободных страниц памяти, которое заносится в переменную free:
Проверка vm.overcommit_memory
Что бы самим увидеть что происходит при vm.overcommit_memory , и как вообще выделяется память — используем простой код:
В строке void *mem_stack = malloc(mem_size) выполняем выделение памяти 4096 байт, которые заданы в переменной mem_size .
Источник