Как решить "java.io.IOException: error = 12, Не удается выделить память", вызывая Runtime # exec () - PullRequest
66 голосов
/ 14 июля 2009

В моей системе я не могу запустить простое приложение 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 ]

35 голосов
/ 22 июня 2010

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

echo 1 > /proc/sys/vm/overcommit_memory
18 голосов
/ 14 июля 2009

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

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

РЕДАКТИРОВАТЬ: Re. Ваше решение для избыточной загрузки позволяет разрешить избыточную загрузку системной памяти, возможно, позволяя процессам распределять (но не использовать) больше памяти, чем фактически доступно. Поэтому я предполагаю, что fork() дублирует память процесса Java, как обсуждалось в комментариях ниже. Конечно, вы не используете память, поскольку 'ls' заменяет дублирующийся процесс Java.

9 голосов
/ 03 февраля 2012

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

Подробнее см. На http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

9 голосов
/ 04 мая 2010

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

8 голосов
/ 21 сентября 2011

Я решил это с помощью 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");
    }
}
8 голосов
/ 14 июля 2009

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

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 ().

5 голосов
/ 01 августа 2010

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

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

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

4 голосов
/ 19 сентября 2012

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

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

4 голосов
/ 10 августа 2011

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

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

4 голосов
/ 21 февраля 2011

overcommit_memory

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

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

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

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

...