【问题标题】:How to solve "java.io.IOException: error=12, Cannot allocate memory" calling Runtime#exec()?如何解决“java.io.IOException: error=12, Cannot allocate memory”调用 Runtime#exec()?
【发布时间】:2009-07-14 11:20:00
【问题描述】:

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

【问题讨论】:

  • 这要么是 linux 版本中的错误,要么是您有一些权限问题。您可以查看源代码中的 UnixProcess:164 以了解它尝试分配的内容。
  • 你可以随时试试sun jdk
  • 我发布了一个免费库的链接,可以解决您的问题,但版主删除了我的答案,没有任何解释。为了社区的利益,我再次尝试评论:Yajsw 解决了您的内存问题,它在 Linux 上使用对 C 库的调用来创建进程。在这里阅读:sourceforge.net/projects/yajsw/forums/forum/810311/topic/…
  • 我在 openjdk 上遇到过这种情况,在我用官方的 sun jdk 替换它之后,fork 工作正常...如果你不想替换 openjdk,'overcommit_memory' hack 也可以

标签: java runtime.exec


【解决方案1】:

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

echo 1 > /proc/sys/vm/overcommit_memory

【讨论】:

  • 当心!将 overcommit_memory 设置为 1,每个 malloc() 都会成功。当您的内存不足时,Linux 将开始随机杀死进程。 win.tue.nl/~aeb/linux/lk/lk-9.html
  • 是否可以将其限制为每个进程,而不是系统范围?
  • 在 Vagrant box 中使用此解决方案进行开发。
  • 是的,这在本地 Vagrant/JDK 环境中也适用于我,同时尝试构建 dom-distiller。必须 sudo su - 获得 root 才能调整 proc 文件系统。
【解决方案2】:

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

我怀疑UnixProcess 执行fork() 并且它根本没有从操作系统获得足够的内存(如果内存可用,它将fork() 复制该进程,然后exec() 在新的内存过程,而且还没有到那个程度)

编辑:回复。您的过度使用解决方案,它允许过度使用系统内存,可能允许进程分配(但不使用)比实际可用更多的内存。所以我猜fork() 复制了 Java 进程内存,如下面的 cmets 中讨论的那样。当然你不使用内存,因为 'ls' 替换了重复的 Java 进程。

【讨论】:

  • 我曾经读过 fork() 调用实际上复制了当前运行进程的整个内存。还是真的吗?如果你有一个 1.2GB 内存和 2GB 总内存的 java 程序,我猜它会失败?
  • 是的。我正要提这个,但我依稀记得现代操作系统会为内存页实现写时复制,所以我不确定
  • 如果她使用默认设置运行应用程序,我猜想复制 64MB 内存应该不是问题。
  • 我认为 Andrea 是一个“他”。这是意大利的男性名字:-)
  • @kd304 是的,这仍然是正确的,但只有内存映射被复制 - 并且内存在新进程中被写入时复制 - 这意味着只有在写入时才会实际复制内存。仍然 - 在使用 大量 内存的大型应用程序服务器中这是一个相当大的问题 - 因为这些服务器往往会导致在 fork 和 exec 之间的小窗口中复制大量内存。
【解决方案3】:

Java 版本 1.6.0_23 及更高版本已解决此问题。

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935查看更多详情

【讨论】:

  • 知道它是否适用于 OpenJDK 或等效的非 Sun JVM?
  • 升级到 1.6.0_37-b06 后我没有遇到这个问题。仍然对错误修复感到困惑。那么 jvm 分配给Runtime.exec 的内存有多少?
  • 好点。升级 JVM 确实解决了这个问题,因为它们现在使用不同的(更轻的)系统调用。
  • 仍然在 1.7.0_91 中得到这个,似乎更多的是我的机器上的内存限制(当其他应用程序关闭时我没有收到这个错误)。另外,exec 会生成与原始进程具有相同 RAM 使用率的新进程
  • @Karussell:你解决了这个问题吗?我在 1.7.0_111 并面临同样的问题。升级到 jdk8 不是一种选择。
【解决方案4】:

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

【讨论】:

  • 我在使用 Maven 时遇到了这个问题。我的机器有 1GB 内存,它运行着 Hudson、Nexus 和另一个 Maven 进程。由于我们在 MAVEN_OPTS 上错误地设置了 -Xms512m,Maven 进程崩溃了。将其修复为 -Xms128m 即可解决。
【解决方案5】:

我发现了这些链接:

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

【讨论】:

    【解决方案6】:

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

    【讨论】:

      【解决方案7】:

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

      迈克尔的回答确实解决了你的问题,但它可能(或者说,最终会)导致操作系统自 1 告诉 OS 以来内存分配问题的死锁不太注意内存分配 & 0 只是猜测 & 显然你很幸运,操作系统猜猜这次你可以有记忆了。下次?嗯.....

      更好的方法是您试验您的情况并提供良好的交换空间并提供更好的物理内存使用率并将值设置为 2 而不是 1 或 0。

      【讨论】:

        【解决方案8】:

        overcommit_memory

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

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

        1 - 总是过度使用。适用于一些科学应用。

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

        【讨论】:

          【解决方案9】:

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

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

          【讨论】:

          • Tanuki 包装纸令人印象深刻。不幸的是,WrapperManager 是专业版的一部分,如果这是您唯一需要的东西,它会非常昂贵。你知道任何免费的替代品吗?
          • @kongo09 它也作为免费 (GPLv2) 社区版的一部分提供。您甚至可以下载源代码并将其用于 GPL 产品中。
          • 我不认为这是社区版的一部分。如果你尝试快速测试,你会得到以下异常:Exception in thread "main" org.tanukisoftware.wrapper.WrapperLicenseError: Requires the Professional Edition.
          【解决方案10】:

          虽然这听起来很奇怪,但一种解决方法是减少分配给 JVM 的内存量。由于 fork() 复制了进程和它的内存,如果你的 JVM 进程真的不需要像通过 -Xmx 分配的那样多的内存,那么分配给 git 的内存就可以了。

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

          【讨论】:

            猜你喜欢
            • 2017-08-12
            • 2011-08-29
            • 2015-09-16
            • 2023-02-09
            • 2019-12-25
            • 2013-12-05
            • 1970-01-01
            • 1970-01-01
            • 2018-02-16
            相关资源
            最近更新 更多