Come risolvere “java.io.IOException: error = 12, Can not allocate memory” chiamando Runtime # exec ()?

Sul mio sistema non riesco a eseguire una semplice applicazione Java che avvia un processo. Non so come risolvere.

Potresti darmi qualche suggerimento su come risolvere?

Il programma è:

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

Il risultato è:

 [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.(UNIXProcess.java:164) at java.lang.ProcessImpl.start(ProcessImpl.java:81) at java.lang.ProcessBuilder.start(ProcessBuilder.java:467) ... 4 more 

Configurazione del sistema:

 [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: Soluzione Questo risolve il mio problema, non so esattamente perché:

echo 0> / proc / sys / vm / overcommit_memory

Up-voti per chi è in grado di spiegare 🙂

Ulteriori informazioni, output superiore:

 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 

Ulteriori informazioni, uscita gratuita:

 [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 

Qual è il profilo di memoria della tua macchina? ad esempio se corri in top , quanta memoria hai a disposizione?

Sospetto che UnixProcess esegua un fork() e semplicemente non UnixProcess abbastanza memoria dal sistema operativo (se la memoria lo serve, fork() duplica il processo e poi exec() per eseguire ls nel nuovo processo di memoria, ed è non arrivare così lontano)

EDIT: Re. la tua soluzione overcommit, permette l’overcommitting della memoria di sistema, permettendo eventualmente ai processi di allocare (ma non utilizzare) più memoria di quella effettivamente disponibile. Quindi suppongo che il fork() duplica la memoria del processo Java come discusso nei commenti qui sotto. Ovviamente non si usa la memoria poiché “ls” sostituisce il processo Java duplicato.

Questa è la soluzione ma devi impostare:

 echo 1 > /proc/sys/vm/overcommit_memory 

Questo è risolto in Java versione 1.6.0_23 e versioni successive.

Vedi maggiori dettagli su http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

Runtime.getRuntime().exec assegna il processo con la stessa quantità di memoria del principale. Se si dispone di heap impostato su 1 GB e si tenta di eseguire exec, verrà assegnato un altro 1 GB per l’esecuzione di tale processo.

Mi sono imbattuto in questi collegamenti:

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

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

Sembra essere un bug. Si consiglia l’uso di un trucco spawn () al posto di plain fork () / exec ().

Ho risolto questo problema utilizzando 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"); } } 

Se guardi nella sorgente di java.lang.Runtime, vedrai exec finalmente chiamare il metodo protetto: execVM, che significa che usa la memoria virtuale. Quindi per il sistema Unix, la VM dipende dalla quantità di spazio di swap + un certo rapporto di memoria fisica.

La risposta di Michael ha risolto il tuo problema ma potrebbe (o per dire, alla fine) causare il deadlock del sistema operativo nel problema di allocazione della memoria dal momento che 1 dice meno attenzione all’allocazione della memoria e 0 è solo una supposizione e ovviamente che sei fortunato che OS supponga di poter avere memoria QUESTA VOLTA. La prossima volta? Hmm …..

Un approccio migliore è che sperimentate il vostro caso e date un buon spazio di scambio e date un rapporto migliore tra la memoria fisica utilizzata e il valore impostato a 2 anziché 1 o 0.

overcommit_memory

Controlla l’overcommit della memoria di sistema, consentendo eventualmente ai processi di allocare (ma non utilizzare) più memoria di quella effettivamente disponibile.

0 – Gestione euristica della manovra. I casi di overcommits evidenti nello spazio degli indirizzi sono rifiutati. Utilizzato per un sistema tipico. Assicura che un’assegnazione seriamente fallita fallisce consentendo al overcommit di ridurre l’utilizzo dello swap. root è autorizzato ad allocare leggermente più memoria in questa modalità. Questo è l’impostazione predefinita.

1 – Sempre overcommit. Adeguato per alcune applicazioni scientifiche.

2 – Non esagerare. Lo spazio totale di indirizzamento per il sistema non può superare lo swap più una percentuale configurabile (il valore predefinito è 50) di RAM fisica. A seconda della percentuale che si utilizza, nella maggior parte delle situazioni ciò significa che un processo non verrà ucciso mentre si tenta di utilizzare la memoria già allocata, ma riceverà gli errori sull’allocazione della memoria come appropriato.

Puoi usare il wrapper Tanuki per generare un processo con spawn POSIX invece di fork. http://wrapper.tanukisoftware.com/doc/english/child-exec.html

La funzione WrapperManager.exec () è un’alternativa a Java-Runtime.exec () che ha lo svantaggio di utilizzare il metodo fork (), che su alcune piattaforms può diventare molto costoso per creare un nuovo processo.

Per quanto strano possa sembrare, uno è quello di ridurre la quantità di memoria allocata alla JVM. Dato che fork () duplica il processo e la sua memoria, se il tuo processo JVM non ha realmente bisogno della quantità di memoria assegnata tramite -Xmx, l’allocazione della memoria su git funzionerà.

Ovviamente puoi provare altre soluzioni qui menzionate (come l’eccesso di commit o l’aggiornamento a una JVM che ha la correzione). Puoi provare a ridurre la memoria se sei alla disperata ricerca di una soluzione che mantenga intatto tutto il software senza alcun impatto sull’ambiente. Ricorda inoltre che ridurre -Xmx in modo aggressivo può causare OOM. Consiglierei l’aggiornamento del JDK come soluzione stabile a lungo termine.