簡體   English   中英

如何解決“java.io.IOException:error = 12,無法分配內存”調用Runtime #exec()?

[英]How to solve “java.io.IOException: error=12, Cannot allocate memory” calling 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> / 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

這是解決方案,但您必須設置:

echo 1 > /proc/sys/vm/overcommit_memory

您的機器的內存配置文件是什么? 例如,如果你跑到top ,你有多少可用內存?

我懷疑UnixProcess執行fork()並且它根本沒有從操作系統獲得足夠的內存(如果內存服務,它將fork()復制進程,然后exec()在新的內存進程中運行ls,並且它是沒那么遠)

編輯:回復。 你的overcommit解決方案,它允許過度使用系統內存,可能允許進程分配(但不使用)比實際可用內存更多的內存。 所以我猜fork()復制了Java進程內存,如下面的評論所述。 當然你不使用內存,因為'ls'取代了重復的Java進程。

Runtime.getRuntime().exec使用與main相同的內存量來分配進程。 如果您將堆設置為1GB並嘗試執行,那么它將為該進程分配另外1GB來運行。

這在Java版本1.6.0_23及更高版本中得到了解決。

有關詳細信息,請訪問http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

我遇到了這些鏈接:

http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html

http://www.nabble.com/Review-request-for-5049299-td23667680.html

似乎是一個bug。 建議使用spawn()技巧而不是普通的fork()/ exec()。

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

如果你查看java.lang.Runtime的源代碼,你會看到exec最后調用protected method:execVM,這意味着它使用虛擬內存。 因此對於類Unix系統,VM取決於交換空間量+某些物理內存比率。

邁克爾的答案確實解決了你的問題,但它可能(或者說,最終會)導致操作系統在內存分配問題上出現死鎖,因為1告訴操作系統不要小心內存分配&0只是猜測並且顯然你很幸運,操作系統猜測你可以這個時候有記憶。 下次? 嗯.....

更好的方法是你試驗你的情況並提供一個良好的交換空間並提供更好的物理內存比率和設置值為2而不是1或0。

聽起來很奇怪,一個解決方法是減少分配給JVM的內存量。 由於fork()復制了進程及其內存,如果你的JVM進程並不真正需要通過-Xmx分配的內存,那么git的內存分配就可以了。

當然,您可以嘗試此處提到的其他解決方案(例如過度提交或升級到具有此修復程序的JVM)。 如果您急需一個能夠保持所有軟件完整且不受環境影響的解決方案,您可以嘗試減少內存。 還要記住,減少-Xmx會積極地導致OOM。 我建議將JDK升級為長期穩定的解決方案。

overcommit_memory

控制系統內存的過度使用,可能允許進程分配(但不使用)比實際可用內存更多的內存。

0 - 啟發式過度使用處理。 地址空間的明顯過度使用被拒絕。 用於典型系統。 它確保嚴重的瘋狂分配失敗,同時允許過度使用以減少交換使用。 root允許在這種模式下分配更多的內存。 這是默認值。

1 - 總是過度使用。 適合某些科學應用。

2 - 不要過度使用。 系統的總地址空間提交不允許超過交換加上物理RAM的可配置百分比(默認值為50)。 根據您使用的百分比,在大多數情況下,這意味着在嘗試使用已分配的內存時不會終止進程,但會在適當時收到內存分配錯誤。

你可以使用Tanuki包裝器來生成一個帶有POSIX spawn而不是fork的進程。 http://wrapper.tanukisoftware.com/doc/english/child-exec.html

WrapperManager.exec()函數是Java-Runtime.exec()的替代方法,它的缺點是使用fork()方法,在某些平台上創建新進程的內存非常昂貴。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM