如何解决调用 Runtime#exec() 的“java.io.IOException:error=12,无法分配内存”?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1124771/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to solve "java.io.IOException: error=12, Cannot allocate memory" calling Runtime#exec()?
提问by Andrea Francia
On my system I can't run a simple Java application that start a process. I don't know how to solve.
在我的系统上,我无法运行启动进程的简单 Java 应用程序。我不知道如何解决。
Could you give me some hints how to solve?
你能给我一些提示如何解决吗?
The program is:
该计划是:
[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");
}
}
The result is:
结果是:
[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
Configuration of the system:
系统配置:
[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)
EDIT: SolutionThis solves my problem, I don't know exactly why:
编辑:解决方案这解决了我的问题,我不知道为什么:
echo 0 > /proc/sys/vm/overcommit_memory
回声 0 > /proc/sys/vm/overcommit_memory
Up-votes for who is able to explain :)
谁能够解释的赞成票:)
Additional informations, top output:
附加信息,顶部输出:
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
Additional informations, free output:
附加信息,免费输出:
[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
采纳答案by Brian Agnew
What's the memory profile of your machine ? e.g. if you run top
, how much free memory do you have ?
您机器的内存配置文件是什么?例如,如果您运行top
,您有多少空闲内存?
I suspect UnixProcess
performs a fork()
and it's simply not getting enough memory from the OS (if memory serves, it'll fork()
to duplicate the process and then exec()
to run the ls in the new memory process, and it's not getting as far as that)
我怀疑UnixProcess
执行 afork()
并且它根本没有从操作系统中获得足够的内存(如果内存可用,它将fork()
复制该进程,然后exec()
在新的内存进程中运行 ls,但它并没有达到那个程度)
EDIT: Re. your overcommit solution, it permits overcommitting of system memory, possibly allowing processes to allocate (but not use) more memory than is actually available. So I guess that the fork()
duplicates the Java process memory as discussed in the comments below. Of course you don't use the memory since the 'ls' replaces the duplicate Java process.
编辑:重新。您的过量使用解决方案,它允许过量使用系统内存,可能允许进程分配(但不使用)比实际可用内存更多的内存。所以我猜这会fork()
复制 Java 进程内存,如下面的评论中所讨论的。当然,您不使用内存,因为 'ls' 替换了重复的 Java 进程。
回答by akarnokd
I came across these links:
我遇到了这些链接:
http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html
http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html
http://www.nabble.com/Review-request-for-5049299-td23667680.html
http://www.nabble.com/Review-request-for-5049299-td23667680.html
Seems to be a bug. Usage of a spawn() trick instead of the plain fork()/exec() is advised.
似乎是一个错误。建议使用 spawn() 技巧而不是普通的 fork()/exec()。
回答by Attila Bukta
Runtime.getRuntime().exec
allocates the process with the same amount of memory as the main. If you had you heap set to 1GB and try to exec then it will allocate another 1GB for that process to run.
Runtime.getRuntime().exec
为进程分配与主进程相同的内存量。如果您将堆设置为 1GB 并尝试执行,那么它将为该进程分配另一个 1GB 以运行。
回答by Michael
This is the solution but you have to set:
这是解决方案,但您必须设置:
echo 1 > /proc/sys/vm/overcommit_memory
回答by Scott Chu
If you look into the source of java.lang.Runtime, you'll see exec finally call protected method: execVM, which means it uses Virtual memory. So for Unix-like system, VM depends on amount of swap space + some ratio of physical memory.
如果你查看 java.lang.Runtime 的源码,你会看到 exec 最后调用了 protected 方法:execVM,这意味着它使用的是虚拟内存。因此,对于类 Unix 系统,VM 取决于交换空间量 + 物理内存的某个比率。
Michael's answer did solve your problem but it might (or to say, would eventually) cause the O.S. deadlock in memory allocation issue since 1 tell O.S. less careful of memory allocation & 0 is just guessing & obviously that you are lucky that O.S. guess you can have memory THIS TIME. Next time? Hmm.....
Michael 的回答确实解决了您的问题,但它可能(或者说,最终会)导致操作系统在内存分配问题上死锁,因为 1 告诉操作系统对内存分配不那么小心,0 只是在猜测,显然你很幸运,操作系统猜测你可以有记忆这一次。下次?唔.....
Better approach is that you experiment your case & give a good swap space & give a better ratio of physical memory used & set value to 2 rather than 1 or 0.
更好的方法是您尝试自己的情况并提供良好的交换空间并提供更好的物理内存使用比率并将值设置为 2 而不是 1 或 0。
回答by ricardofunke
overcommit_memory
过量使用内存
Controls overcommit of system memory, possibly allowing processes to allocate (but not use) more memory than is actually available.
控制系统内存的过度使用,可能允许进程分配(但不使用)比实际可用内存更多的内存。
0 - Heuristic overcommit handling. Obvious overcommits of address space are refused. Used for a typical system. It ensures a seriously wild allocation fails while allowing overcommit to reduce swap usage. root is allowed to allocate slighly more memory in this mode. This is the default.
0 - 启发式过量使用处理。明显的地址空间过度使用被拒绝。用于典型系统。它确保严重的疯狂分配失败,同时允许过度使用以减少交换使用。在这种模式下允许 root 分配更多的内存。这是默认设置。
1 - Always overcommit. Appropriate for some scientific applications.
1 - 总是过量使用。适用于某些科学应用。
2 - Don't overcommit. The total address space commit for the system is not permitted to exceed swap plus a configurable percentage (default is 50) of physical RAM. Depending on the percentage you use, in most situations this means a process will not be killed while attempting to use already-allocated memory but will receive errors on memory allocation as appropriate.
2 - 不要过度使用。系统的总地址空间提交不允许超过交换加上物理 RAM 的可配置百分比(默认为 50)。根据您使用的百分比,在大多数情况下,这意味着进程在尝试使用已分配的内存时不会被终止,但会在适当的内存分配中收到错误。
回答by Dan Fabulich
You can use the Tanuki wrapper to spawn a process with POSIX spawn instead of fork. http://wrapper.tanukisoftware.com/doc/english/child-exec.html
您可以使用 Tanuki 包装器通过 POSIX spawn 而不是 fork 来生成进程。http://wrapper.tanukisoftware.com/doc/english/child-exec.html
The WrapperManager.exec()function is an alternative to the Java-Runtime.exec() which has the disadvantage to use the fork() method, which can become on some platforms very memory expensive to create a new process.
所述WrapperManager.exec()函数是具有的缺点为使用fork()的方法,该方法可以成为在某些平台上非常昂贵存储器要创建新的进程的替代Java的的Runtime.exec()。
回答by kongo09
I solved this using JNA: https://github.com/twall/jna
我使用 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");
}
}
回答by Alf H?gemark
This is solved in Java version 1.6.0_23 and upwards.
这已在 Java 1.6.0_23 及更高版本中解决。
See more details at http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935
在http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935查看更多详细信息
回答by Deepak Bala
As weird as this may sound, one work around is to reduce the amount of memory allocated to the JVM. Since fork() duplicates the process and its memory, if your JVM process does not really need as much memory as is allocated via -Xmx, the memory allocation to git will work.
尽管这听起来很奇怪,但一种解决方法是减少分配给 JVM 的内存量。由于 fork() 复制了进程及其内存,如果您的 JVM 进程确实不需要像通过 -Xmx 分配的那么多内存,那么分配给 git 的内存将起作用。
Of course you can try other solutions mentioned here (like over-committing or upgrading to a JVM that has the fix). You can try reducing the memory if you are desperate for a solution that keeps all software intact with no environment impact. Also keep in mind that reducing -Xmx aggressively can cause OOMs. I'd recommend upgrading the JDK as a long-term stable solution.
当然,您可以尝试这里提到的其他解决方案(例如过度提交或升级到具有修复功能的 JVM)。如果您迫切需要一种可以在不影响环境的情况下保持所有软件完好无损的解决方案,您可以尝试减少内存。还要记住,积极减少 -Xmx 会导致 OOM。我建议升级 JDK 作为长期稳定的解决方案。