Как решить "java.io. IOException: error=12, не удается выделить память" вызов Runtime#exec()?


в моей системе я не могу запустить простое приложение Java, которое запускает процесс. Я не знаю как решить.

не могли бы вы дать мне некоторые подсказки, как решить?

программа:

[root@newton sisma-acquirer]# cat prova.java
import java.io.IOException;

public class prova {

   public static void main(String[] args) throws IOException {
        Runtime.getRuntime().exec("ls");
    }

}

результат:

[root@newton 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

Конфигурация системы:

[root@newton 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)
[root@newton sisma-acquirer]# cat /etc/fedora-release
Fedora release 10 (Cambridge)

изменить: решение Это решает мою проблему, я не знаю точно почему:

echo 0 > /proc/sys/vm / overcommit_memory

голосов ибо кто может объяснить :)

дополнительная информация, верхний выход:

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

дополнительная информация, свободный выход:

[root@newton sisma-acquirer]# free
             total       used       free     shared    buffers     cached
Mem:       1033456     588548     444908          0      51704     188292
-/+ buffers/cache:     348552     684904
Swap:      2031608          0    2031608
10 66

10 ответов:

что профиль памяти вашей машины ? например, если вы запустите top, сколько свободной памяти у вас есть ?

Я подозреваю UnixProcess выполняет fork() и это просто не получает достаточно памяти от ОС (если память служит, это будет fork() чтобы дублировать процесс, а затем exec() чтобы запустить ls в новом процессе памяти, и это не доходит до этого)

EDIT: Re. ваше решение так, например, она допускает перераспределение системной памяти, возможно, позволят процессы, чтобы выделить (но не использовать) больше памяти, чем на самом деле доступно. Так что я думаю, что fork() дублирует память процесса Java, как описано в комментариях ниже. Конечно, вы не используете память, так как " ls " заменяет дубликат процесса Java.

Это решение, но вы должны установить:

echo 1 > /proc/sys/vm/overcommit_memory

Это решается в Java версии 1.6.0_23 и выше.

подробнее http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

Runtime.getRuntime().exec выделяет процесс с тем же объемом памяти, что и основной. Если у вас была куча, установленная на 1 ГБ, и попробуйте выполнить, то она выделит еще 1 ГБ для запуска этого процесса.

я наткнулся на эти ссылки:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html

http://www.nabble.com/Review-request-for-5049299-td23667680.html

кажется, ошибка. Рекомендуется использовать трюк spawn() вместо простой вилки()/exec ().

Я решил это с помощью 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");
    }
}

Если вы посмотрите в источник java.ленг.Во время выполнения вы увидите, что exec наконец вызывает защищенный метод: execVM, что означает, что он использует виртуальную память. Таким образом, для Unix-подобной системы VM зависит от объема пространства подкачки + некоторого соотношения физической памяти.

ответ Майкла действительно решил вашу проблему, но это может (или сказать, в конечном итоге) привести к тупику O. S. В проблеме выделения памяти, так как 1 говорит O. S. менее осторожное выделение памяти & 0 просто угадывает & очевидно, что вам повезло думаю, на этот раз у тебя будет память. В следующий раз? Хм.....

лучший подход заключается в том, что вы экспериментируете с вашим случаем и даете хорошее пространство подкачки и даете лучшее соотношение используемой физической памяти и устанавливаете значение 2, а не 1 или 0.

overcommit_memory

управляет перегрузкой системной памяти, возможно, позволяя процессам выделять (но не использовать) больше памяти, чем на самом деле доступно.

0-эвристическая перегрузка. Очевидные перерасходы адресного пространства отвергаются. Используется для типичной системы. Это гарантирует, что серьезно дикое распределение терпит неудачу, позволяя overcommit уменьшить использование свопа. root позволяет выделять незначительно больше памяти в этом режиме. Это по умолчанию.

1 - всегда перерасход. Подходит для некоторых научных применений.

2-Не переусердствуйте. Общая фиксация адресного пространства для системы не может превышать swap плюс настраиваемый процент (по умолчанию 50) физической ОЗУ. В зависимости от используемого процента, в большинстве случаев это означает, что процесс не будет убит при попытке использовать уже выделенную память, но будет получать ошибки при выделении памяти по мере необходимости.

вы можете использовать оболочку Tanuki для создания процесса с помощью POSIX spawn вместо fork. http://wrapper.tanukisoftware.com/doc/english/child-exec.html

The WrapperManager.exec () функция является альтернативой Java-Runtime.exec (), который имеет недостаток в использовании метода fork (), который может стать на некоторых платформах очень дорогой памятью для создания нового процесса.

Как бы странно это ни звучало, одна работа заключается в уменьшении объема памяти, выделенной для JVM. Поскольку fork () дублирует процесс и его память, Если вашему процессу JVM действительно не нужно столько памяти, сколько выделено через-Xmx, выделение памяти для git будет работать.

конечно, вы можете попробовать другие решения, упомянутые здесь (например, чрезмерная фиксация или обновление до JVM, которая имеет исправление). Вы можете попробовать уменьшить память, если вы отчаянно нуждаетесь в решении, которое сохраняет все программное обеспечение нетронутым без воздействия на окружающую среду. Также имейте в виду, что уменьшение-Xmx агрессивно может вызвать OOMs. Я бы рекомендовал обновить JDK как долгосрочное стабильное решение.