2013年7月

java.io.IOException: error=12, Cannot allocate memory

有时我们需要在java中执行一些bash命令,可以通过Java的ProcessBuilder与Runtime.getRuntime().exec()来实现。一般在其它语言中执行一个bash命令时,需要首先调用fork(),通过复制当前过程来创建一个子进程。然后调用exec()来改变进程的执行内容,实际上是在子进程执行不同的代码。

在java中创建新进程时报错:java.io.IOException: error=12, Cannot allocate memory,这个问题其实是fork()的时候产生的。

当使用Java创建一个新进程时,需要复制整个Java JVM,所以我们需要申请与JVM内存大小相等的新内存。当我们在一个内存不太充足的机器上,假如有512M内存,并且JVM占用了350M内存,如果此时去创建一个新的进程,则需要申请新的350M内存,但机器的内存只有512M,已经不足以提供新进程所需要的350M内存,即使我们只执行一条很简单的命令: ls, “ls”命令本身并不需要使用到350M内存,但是要执行它却需要向内存申请350M。

Over-commit

每次在fork()的时候,操作系统会检查是否有足够的内存提供给子线程,我们可以把这个安全检查关闭,让操作系统在即使没有足够内存的情况下也允许我们创建出来子线程。因为我们执行的命令不需要那么大的内存,因此系统能够正常运行下来。启用操作系统的over-commit功能我们可以解决这个问题。

临时性的打开over-commit:

echo 1 > /proc/sys/vm/overcommit_memory

计算机启动时打开over-commit,编辑 /etc/sysctl.conf 添加下面的行:

vm.overcommit_memory = 1

更多相关阅读:
Forking the JVM
How to solve “java.io.IOException: error=12, Cannot allocate memory” calling Runtime#exec()?