如何解决“java.io.IOException:error = 12,无法分配内存”调用Runtime #exec()?

时间:2009-07-14 11:20:01

标签: java 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&gt;的/ 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 个答案:

答案 0 :(得分:35)

这是解决方案,但您必须设置:

echo 1 > /proc/sys/vm/overcommit_memory

答案 1 :(得分:18)

您机器的内存配置文件是什么?例如如果你运行top,你有多少可用内存?

我怀疑UnixProcess执行fork()并且它根本没有从操作系统获得足够的内存(如果内存服务,它将fork()复制进程然后{{1}在新的内存进程中运行ls,并没有达到那个程度)

编辑:Re。你的overcommit解决方案,它允许过度使用系统内存,可能允许进程分配(但不使用)比实际可用内存更多的内存。所以我想exec()重复了Java进程内存,如下面的评论所述。当然你不使用内存,因为'ls'取代了重复的Java进程。

答案 2 :(得分:9)

Runtime.getRuntime().exec使用与main相同的内存量分配进程。如果您将堆设置为1GB并尝试执行,那么它将为该进程分配另外1GB来运行。

答案 3 :(得分:9)

这是在Java版本1.6.0_23及更高版本中解决的。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

上查看更多详情

答案 4 :(得分:8)

我遇到了这些链接:

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 :(得分:8)

我使用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");
    }
}

答案 6 :(得分:5)

如果你查看java.lang.Runtime的源代码,你会看到exec最后调用protected method:execVM,这意味着它使用了虚拟内存。因此,对于类Unix系统,VM取决于交换空间量+某些物理内存比率。

迈克尔的答案确实解决了你的问题,但它可能(或者说,最终会)导致O.S.内存分配问题中的死锁问题从1开始就告诉O.S.不太注意内存分配和0只是猜测&amp;显然你很幸运,O.S。猜猜你现在可以有记忆了。下次?嗯.....

更好的方法是你试验你的案例&amp;提供良好的交换空间&amp;提供更好的物理内存比率和将值设置为2而不是1或0。

答案 7 :(得分:4)

overcommit_memory

控制系统内存的过度使用,可能允许进程分配(但不使用)比实际可用内存更多的内存。

0 - 启发式过度使用处理。地址空间的明显过度使用被拒绝。用于典型系统。它确保严重的疯狂分配失败,同时允许过度使用以减少交换使用。 root允许在这种模式下分配更多的内存。这是默认值。

1 - 总是过度使用。适合某些科学应用。

2 - 不要过度使用。系统的总地址空间提交不允许超过交换加上物理RAM的可配置百分比(默认值为50)。根据您使用的百分比,在大多数情况下,这意味着在尝试使用已分配的内存时不会终止进程,但会在内存分配时收到相应的错误。

答案 8 :(得分:4)

您可以使用Tanuki包装器生成POSIX spawn而不是fork的进程。 http://wrapper.tanukisoftware.com/doc/english/child-exec.html

  

WrapperManager.exec()函数是Java-Runtime.exec()的替代方法,它缺点是使用fork()方法,在某些平台上创建新进程的内存非常昂贵。

答案 9 :(得分:4)

听起来很奇怪,一个解决方法是减少分配给JVM的内存量。由于fork()复制了进程及其内存,如果你的JVM进程并不真正需要通过-Xmx分配的内存,那么git的内存分配就可以了。

当然,您可以尝试此处提到的其他解决方案(例如过度提交或升级到具有此修复程序的JVM)。如果您急需一个能够保持所有软件完整且不受环境影响的解决方案,您可以尝试减少内存。还要记住,减少-Xmx会积极地导致OOM。我建议将JDK升级为长期稳定的解决方案。