fork() с ошибкой "Недостаточно памяти"
Родительский процесс завершается ошибкой с errno=12(Недостаточно памяти), когда он пытается обработать дочерний процесс. Родительский процесс выполняется на ядре Linux 3.0 - SLES 11. В момент разветвления дочернего процесса родительский процесс уже использовал около 70% ОЗУ (180 ГБ /256 ГБ). Есть ли решение этой проблемы?
Приложение написано на C++, скомпилировано с g++ 4.6.3.
2 ответа
Возможно, в вашей системе предотвращена фиксация виртуальной памяти.
Если это предотвращено, то виртуальная память не может быть больше, чем размер физической RAM + swap. Если это разрешено, то виртуальная память может быть больше, чем RAM + swap.
Когда ваш процесс разветвляется, ваши процессы (родительский и дочерний) будут иметь 2*180 ГБ виртуальной памяти (это слишком много, если у вас нет свопинга).
Итак, разрешите over commit следующим образом:
echo 1 > /proc/sys/vm/overcommit_memory
Это должно помочь, если дочерний процесс выполняется немедленно или освобождает выделенную память до того, как родительский файл пишет слишком много в собственную память. Так что будьте осторожны, убийца нехватки памяти может действовать, если оба процесса продолжают использовать всю память.
Страница man proc(5) гласит:
/ Proc/ SYS / VM / overcommit_memory
Этот файл содержит режим учета виртуальной памяти ядра. Значения: 0: эвристический overcommit (это значение по умолчанию) 1: всегда overcommit, никогда не проверять 2: всегда check, никогда не overcommit
В режиме 0 вызовы mmap(2) с MAP_NORESERVE не проверяются, и проверка по умолчанию очень слабая, что приводит к риску получения процесса "OOM-kill". В Linux 2.4 любое ненулевое значение подразумевает режим 1. В режиме 2 (доступно после Linux 2.6) общее виртуальное адресное пространство в системе ограничено (SS + RAM*(r/100)), где SS - размер пространство подкачки, RAM - это размер физической памяти, а r - содержимое файла /proc/sys/vm/overcommit_ratio.
Больше информации здесь: Overcommit Memory в SLES
fork
-ing требует ресурсов, так как это копирование записываемых страниц процесса. Прочитайте еще раз справочную страницу fork(2).
Вы могли бы по крайней мере предоставить огромный временный файл подкачки. Вы можете создать (в некоторой файловой системе с достаточно места) огромный файл $SWAPFILE
с
dd if=/dev/zero of=$SWAPFILE bs=1M count=256000
mkswap $SWAPFILE
swapon $SWAPFILE
В противном случае, вы можете, например, разработать свою программу по-другому, например, mmap
-на большой файл (и munmap
- перед самым разветвлением, и mmap
- снова после) или, более просто, начиная с начала вашей программы: popen
оболочка, или p2open
или сделать явно pipe
-s к и от него (вероятно, вызов мультиплексирования а-ля poll
также было бы полезно), и позже выдавайте ему команды.
Может быть, мы могли бы помочь больше, если бы у нас было представление о том, что делает ваша программа, почему она потребляет так много памяти, и почему и что она разветвляется...
Читайте http://advancedlinuxprogramming.com/ для получения дополнительной информации.
PS.
если ты fork
просто бежать gdb
чтобы показать обратную трассировку, рассмотрим более простые альтернативы, такие как недавняя библиотека GCC или библиотека libbacktrace Вольфа...
Более приятным решением в Linux было бы использование vfork или posix_spawn (поскольку он будет пытаться использовать vfork, если это возможно): vfork "создает новые процессы без копирования таблиц страниц родительского процесса", поэтому он будет работать, даже если ваше приложение использует больше доступно более 50% оперативной памяти.
Обратите внимание, что std::system и QProcess::execute также используют fork под капотом, есть даже сообщение об этой проблеме в Qt framework: https://bugreports.qt.io/browse/QTBUG-17331