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


67

在我的系统上,我无法运行启动流程的简单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)

编辑:解决方案 这解决了我的问题,我不知道为什么:

回声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

这可能是Linux版本中的错误,或者您有一些特权问题。您可以查看源代码中的UnixProcess:164来找出它试图分配的内容。
akarnokd

1
您随时可以尝试使用sun jdk
wds

我已经发布了一个免费图书馆的链接,该链接可以解决您的问题,但主持人删除了我的回答而没有解释。为了使社区受益,我再次尝试作为评论:Yajsw解决了您的内存问题,在Linux上Yajsw使用对C库的调用来创建进程。阅读在这里:sourceforge.net/projects/yajsw/forums/forum/810311/topic/...
kongo09

我在openjdk中遇到了这个问题,在我用正式的sun jdk替换了它之后,forking可以正常工作...如果您不想替换openjdk,则“
overcommit_memory

Answers:


21

您的机器的内存配置文件是什么?例如,如果您跑步top,您将拥有多少可用内存?

我怀疑UnixProcess执行afork()只是从操作系统中获取不到足够的内存(如果有内存,它将fork()复制该进程,然后exec()在新的内存进程中运行ls,而且还没有达到目的)

编辑:重新。您的过量使用解决方案,它允许过量使用系统内存,可能允许进程分配(但不使用)比实际可用内存更多的内存。因此,我猜想这些fork()重复项将复制Java进程内存,如下面的注释中所述。当然,您不使用内存,因为'ls'代替了重复的Java进程。


我曾经读过fork()调用实际上复制了当前正在运行的进程的整个内存。还是这样吗?如果您有一个Java程序,其内存为1.2 GB,总容量为2GB,我想它会失败吗?
akarnokd

2
是。我要提到这一点,但我依稀记得,现代的操作系统将实施写入时复制的内存页,所以我的这个不知道
布莱恩·阿格纽

如果她使用默认设置运行该应用程序,那么我猜将64MB内存复制就应该不是问题。
akarnokd

21
我认为安德里亚是个“他”。这是意大利的男性名字:-)
Brian Agnew

@ kd304是的,这仍然是正确的,尽管仅复制了内存映射-并且在新进程中将内存写入后复制-意味着仅在写入内存后才实际复制内存。仍然-在使用大量内存的大型应用服务器中这是一个很大的问题-因为这些服务器往往会导致大量内存在fork和exec之间的小窗口中复制。

37

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

echo 1 > /proc/sys/vm/overcommit_memory

27
谨防!将overcommit_memory设置为1时,每个malloc()都会成功。当您的内存不足时,Linux将开始随机终止进程。win.tue.nl/~aeb/linux/lk/lk-9.html
Dan Fabulich 2011年

1
是否可以将其限制为每个进程,而不是整个系统?
Mark McDonald

1
在Vagrant盒中开发中使用此解决方案。
弗朗索瓦博索莱伊

是的,这在本地Vagrant / JDK环境中也对我有用,同时尝试构建dom-distiller。必须sudo su -获得root才能调整proc文件系统。
大富翁

9

在Java 1.6.0_23及更高版本中解决了此问题。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935中查看更多详细信息


知道是否适用于OpenJDK或等效的非Sun JVM吗?
Mark McDonald

我升级到1.6.0_37-B06 ..还是无法了解该bug修复后,我没有得到这个问题..因此,有多少JVM的内存分配给Runtime.exec
Satish Pandey,2012年

优点。升级JVM确实解决了该问题,因为他们现在使用其他(更轻便)的系统调用。
2013年

1
仍然在1.7.0_91上获得此消息,似乎对我的计算机有更多的内存限制(当其他应用程序关闭时,我没有收到此错误)。加上exec产生了与原始进程相同的RAM使用率的新进程
Karussell,2016年

@Karussell:您能解决这个问题吗?我在1.7.0_111上并且面临相同的问题。不能升级到jdk8。
saurabheights

9

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


2
我在Maven中遇到了这个问题。我的机器有1GB内存,并且正在运行Hudson,Nexus和另一个Maven进程。由于我们在MAVEN_OPTS上错误地设置了-Xms512m,因此Maven进程崩溃了。将其修复为-Xms128m即可解决。
阿萨夫·梅西卡


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

5

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

Michael的回答确实解决了您的问题,但是它可能(或者说,最终会)导致内存分配问题中的OS死锁,因为1告诉OS对内存分配的谨慎程度较低,而0只是在猜测,很显然,您很幸运OS猜测您可以这段时间有记忆。下次?嗯...

更好的方法是试验案例并提供良好的交换空间,并提供更好的已用物理内存比率,并将值设置为2,而不是1或0。


4

overcommit_memory

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

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

1-始终过量使用。适用于某些科学应用。

2-不要过度使用。不允许为系统分配的总地址空间超过swap加上物理RAM的可配置百分比(默认为50)。在大多数情况下,这取决于您使用的百分比,这意味着在尝试使用已分配的内存时进程不会被杀死,但是会在适当的内存分配中收到错误。


4

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

所述WrapperManager.exec()函数是具有的缺点为使用fork()的方法,该方法可以成为在某些平台上非常昂贵存储器要创建新的进程的替代Java的的Runtime.exec()。


狸小包装非常令人印象深刻。不幸的WrapperManager是,这是Professional Edition的一部分,如果这是您唯一需要的东西,那么它会非常昂贵。您知道免费的替代品吗?
kongo09 2011年

@ kongo09它也可以作为免费(GPLv2)社区版的一部分获得。您甚至可以下载源代码并在GPL产品中使用它。
Dan Fabulich 2011年

我认为这不是社区版的一部分。如果您尝试进行快速测试,则会遇到以下异常:Exception in thread "main" org.tanukisoftware.wrapper.WrapperLicenseError: Requires the Professional Edition.
kongo09 2011年

4

听起来很奇怪,一种解决方法是减少分配给JVM的内存量。由于fork()复制了该进程及其内存,因此,如果您的JVM进程实际上并不需要通过-Xmx分配的内存,则分配给git的内存将起作用。

当然,您可以尝试这里提到的其他解决方案(例如过量使用或升级到具有此修复程序的JVM)。如果您迫切需要一个可以在不影响环境的情况下保持所有软件完整的解决方案,可以尝试减少内存。还请记住,主动减小-Xmx会导致OOM。我建议升级JDK作为长期稳定的解决方案。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.