Ориен правильно, это системный вызов fork (), запускаемый ProcessBuilder или Runtime.exec или другими средствами JVM, выполняющими внешний процесс (например, другой JVM, выполняющий ant, команду git и т. Д.).
В списках рассылки Jenkins было несколько сообщений об этом: Не удается запустить программу "git" ... error = 12, Невозможно выделить память
В списке разработчиков SCons есть хорошее описание проблемы: fork () + exec () против posix_spawn ()
Существует давний отчет об ошибках JVM с решениями: используйте posix_spawn, а не fork на S10, чтобы избежать исчерпания свопинга . Но я не уверен, что это действительно вошло в JDK7, поскольку комментарии предполагают, что это был план.
Итак, в Unix-подобных системах, когда одному процессу (например, JVM) необходимо запустить другой процесс (например, git), выполняется системный вызов, fork()
который эффективно дублирует текущий процесс и всю его память (Linux и другие оптимизируют это с помощью копирования). -на записи, чтобы память фактически не копировалась, пока ребенок не попытается записать в нее). Затем дублирующий процесс выполняет другой системный вызов, exec()
чтобы запустить другой процесс (например, git), после чего вся эта скопированная память из родительского процесса может быть отброшена операционной системой. Если родительский процесс использует большие объемы памяти (как это обычно делают процессы JVM), вызов fork()
может завершиться ошибкой, если операционная система определит, что ему не хватает памяти + swap для хранения двух копий, даже если дочерний процесс никогда не будет фактически использовать эту скопированную память.
Есть несколько решений:
Добавьте больше физической памяти / RAM к машине.
Добавьте больше пространства подкачки, чтобы обманным путем заставить fork()
работать, даже если пространство подкачки ни в чем не нуждается строго. Это решение, которое я выбрал, потому что довольно легко добавить файл подкачки, и я не хотел мириться с возможностью того, что процессы будут убиты из-за чрезмерной загрузки.
В Linux включите overcommit_memory
опцию системы vm ( / proc / sys / vm / overcommit_memory ). При использовании overcommit вызов fork()
всегда будет успешным, и поскольку дочерний процесс фактически не будет использовать эту копию памяти, все в порядке. Конечно, возможно, что при чрезмерной загрузке ваши процессы будут пытаться использовать больше памяти, чем доступно, и будут убиты ядром. Уместно ли это, зависит от других применений машины. Критически важные машины, вероятно, не должны рисковать убийцей нехватки памяти. Но внутренний сервер разработки, который может позволить себе некоторое время простоя, был бы хорошим местом для включения overcommit.
Измените JVM, чтобы не использовать fork()
+, exec()
но использовать, posix_spawn()
когда доступно. Это решение, запрошенное в отчете об ошибках JVM выше и упомянутое в списке рассылки SCons. Это также реализовано в java_posix_spawn .
Я пытаюсь выяснить, было ли это исправление внесено в JDK7. Если нет, мне интересно, будут ли люди из Дженкинса заинтересованы в такой работе, как java_posix_spawn. Кажется, были попытки интегрировать это в Apache commons-exec .
Programmieraffe, я не уверен на 100%, но ваша ссылка предполагает, что это исправление в JDK7 и JDK6 1.6.0_23 и более поздних версиях. Для записи я использовал OpenJDK 1.6.0_18.
См. Https://stackoverflow.com/questions/1124771/how-to-solve-java-io-ioexception-error-12-cannot-allocate-memory-calling-run