Как решить "java.io.IOException: ошибка = 12, Невозможно выделить память" вызов Runtime # exec()?
В моей системе я не могу запустить простое Java-приложение, которое запускает процесс. Я не знаю, как решить.
Не могли бы вы дать мне подсказки, как решить?
Программа:
[[email protected] sisma-acquirer]# cat prova.java
import java.io.IOException;
public class prova {
public static void main(String[] args) throws IOException {
Runtime.getRuntime().exec("ls");
}
}
Результат:
[[email protected] sisma-acquirer]# javac prova.java && java -cp . prova
Exception in thread "main" java.io.IOException: Cannot run program "ls": java.io.IOException: error=12, Cannot allocate memory
at java.lang.ProcessBuilder.start(ProcessBuilder.java:474)
at java.lang.Runtime.exec(Runtime.java:610)
at java.lang.Runtime.exec(Runtime.java:448)
at java.lang.Runtime.exec(Runtime.java:345)
at prova.main(prova.java:6)
Caused by: java.io.IOException: java.io.IOException: error=12, Cannot allocate memory
at java.lang.UNIXProcess.<init>(UNIXProcess.java:164)
at java.lang.ProcessImpl.start(ProcessImpl.java:81)
at java.lang.ProcessBuilder.start(ProcessBuilder.java:467)
... 4 more
Конфигурация системы:
[[email protected] sisma-acquirer]# java -version
java version "1.6.0_0"
OpenJDK Runtime Environment (IcedTea6 1.5) (fedora-18.b16.fc10-i386)
OpenJDK Client VM (build 14.0-b15, mixed mode)
[[email protected] sisma-acquirer]# cat /etc/fedora-release
Fedora release 10 (Cambridge)
EDIT: решение
Это решает мою проблему, я не знаю точно, почему:
echo 0 > /proc/sys/vm/overcommit_memory
Up-votes для тех, кто может объяснить:)
Дополнительная информация, верхний вывод:
top - 13:35:38 up 40 min, 2 users, load average: 0.43, 0.19, 0.12
Tasks: 129 total, 1 running, 128 sleeping, 0 stopped, 0 zombie
Cpu(s): 1.5%us, 0.5%sy, 0.0%ni, 94.8%id, 3.2%wa, 0.0%hi, 0.0%si, 0.0%st
Mem: 1033456k total, 587672k used, 445784k free, 51672k buffers
Swap: 2031608k total, 0k used, 2031608k free, 188108k cached
Дополнительная информация, свободный выход:
[[email protected] sisma-acquirer]# free
total used free shared buffers cached
Mem: 1033456 588548 444908 0 51704 188292
-/+ buffers/cache: 348552 684904
Swap: 2031608 0 2031608
Ответы
Ответ 1
Каков профиль памяти вашей машины? например если вы запустите top
, сколько свободной памяти у вас есть?
Я подозреваю, что UnixProcess
выполняет a fork()
, и он просто не получает достаточного количества памяти из ОС (если память обслуживается, он будет fork()
дублировать процесс, а затем exec()
, чтобы запустить ls в новом памяти, и это не доходит до этого)
EDIT: Re. ваше решение overcommit, оно позволяет переопределять системную память, что позволяет процессам распределять (но не использовать) больше памяти, чем доступно на самом деле. Поэтому я предполагаю, что fork()
дублирует память процесса Java, как описано в комментариях ниже. Конечно, вы не используете память, так как "ls" заменяет повторяющийся процесс Java.
Ответ 2
Это решение, но вы должны установить:
echo 1 > /proc/sys/vm/overcommit_memory
Ответ 3
Runtime.getRuntime().exec
выделяет процесс с тем же объемом памяти, что и основной. Если у вас была куча, установленная в 1 ГБ, и попробуйте выполнить exec, тогда она выделит еще 1 ГБ для запуска этого процесса.
Ответ 4
Это решается в Java версии 1.6.0_23 и выше.
Подробнее см. http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935
Ответ 5
Я наткнулся на эти ссылки:
http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html
http://www.nabble.com/Review-request-for-5049299-td23667680.html
Кажется, это ошибка. Рекомендуется использовать трюк spawn() вместо простой fork()/exec().
Ответ 6
Я решил это с помощью JNA: https://github.com/twall/jna
import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
public class prova {
private interface CLibrary extends Library {
CLibrary INSTANCE = (CLibrary) Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);
int system(String cmd);
}
private static int exec(String command) {
return CLibrary.INSTANCE.system(command);
}
public static void main(String[] args) {
exec("ls");
}
}
Ответ 7
Если вы посмотрите на источник java.lang.Runtime, вы увидите exec finally call protected method: execVM, что означает, что он использует виртуальную память. Таким образом, для Unix-подобной системы VM зависит от количества пространства подкачки + некоторого соотношения физической памяти.
Ответ Майкла разрешил вашу проблему, но он мог (или, скажем, в конечном итоге) вызвать O.S. тупик в вопросе распределения памяти, поскольку 1 рассказать O.S. менее осторожны в распределении памяти, а 0 просто догадывается и, очевидно, вам повезло, что O.S. Угадайте, у вас может быть память ЭТОТ ВРЕМЯ. В следующий раз? Хм.....
Лучший подход заключается в том, что вы экспериментируете с вашим делом и предоставляете хорошее пространство подкачки и получаете лучшее соотношение используемой физической памяти и задаете значение 2, а не 1 или 0.
Ответ 8
overcommit_memory
Управляет перекомпоновкой системной памяти, что позволяет процессам распределять (но не использовать) больше памяти, чем доступно на самом деле.
0 - Эвристическая обработка с превышением. Очевидным недостаткам адресного пространства отказано. Используется для типичной системы. Это гарантирует, что серьезное несанкционированное распределение не удастся, позволяя скомпенсировать сокращение использования свопов. root разрешает выделять в этом режиме больше памяти. Это значение по умолчанию.
1 - Всегда перекомпилировать. Подходит для некоторых научных приложений.
2 - Не перекомпилируйте. Суммарному фиксации адресного пространства для системы не разрешается превышать своп плюс настраиваемый процент (по умолчанию - 50) физической ОЗУ. В зависимости от процента, который вы используете, в большинстве случаев это означает, что процесс не будет убит при попытке использовать уже выделенную память, но при необходимости получит ошибки в распределении памяти.
Ответ 9
Вы можете использовать обертку Tanuki, чтобы создать процесс с помощью POSIX, вместо вилки. http://wrapper.tanukisoftware.com/doc/english/child-exec.html
Функция WrapperManager.exec() является альтернативой Java-Runtime.exec(), которая имеет недостаток в использовании fork (), который может стать на некоторых платформах очень дорогостоящим для создания нового процесса.
Ответ 10
Как ни странно, как это может звучать, одна работа заключается в уменьшении объема памяти, выделенной для JVM. Поскольку fork() дублирует процесс и его память, если вашему процессу JVM не требуется столько памяти, сколько выделено через -Xmx, будет выделено выделение памяти git.
Конечно, вы можете попробовать другие решения, упомянутые здесь (например, перебор или обновление JVM с исправлением). Вы можете попытаться уменьшить память, если отчаянно нуждаетесь в решении, которое сохраняет все программное обеспечение без ущерба для окружающей среды. Также имейте в виду, что уменьшение -Xmx настойчиво может вызвать OOM. Я бы рекомендовал модернизировать JDK как долговременное стабильное решение.
Ответ 11
Простое убийство сработало для меня.
Do
free -m
чтобы проверить, сколько памяти доступно.
Убейте некоторые задания, которые не требуются.