Comment résoudre "java. io. IOException: error = 12, impossible d'allouer de la mémoire" appelant Runtime#exec ()?
Sur mon système, Je ne peux pas exécuter une simple application Java qui démarre un processus. Je ne sais pas comment le résoudre.
Pourriez-vous me donner quelques conseils sur la façon de résoudre?
Le programme est:
[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");
}
}
Le résultat est:
[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 du système:
[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)
Modifier: Solution Cela résout mon problème, je ne sais pas exactement pourquoi:
Echo 0 > / proc / sys/vm / overcommit_memory
Jusqu'-les votes pour qui est capable d'expliquer :)
Supplémentaires informations, sortie supérieure:
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
Informations supplémentaires, sortie libre:
[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
10 réponses
Quel est le profil mémoire de votre machine ? par exemple, si vous exécutez top
, combien de mémoire libre avez-vous ?
Je soupçonne que UnixProcess
effectue un fork()
et qu'il n'obtient tout simplement pas assez de mémoire du système d'exploitation (si la mémoire sert, il va fork()
dupliquer le processus, puis {[4] } pour exécuter le ls dans le nouveau processus de mémoire, et il ne va pas aussi loin que cela)
Modifier: Re. votre solution de surcommission, elle permet la surcommission de la mémoire système, permettant éventuellement aux processus d'allouer (mais pas utilisez) plus de mémoire que ce qui est réellement disponible. Donc, je suppose que le fork()
duplique la mémoire du processus Java comme discuté dans les commentaires ci-dessous. Bien sûr, vous n'utilisez pas la mémoire puisque le ' ls ' remplace le processus Java en double.
C'est la solution, mais vous devez préciser:
echo 1 > /proc/sys/vm/overcommit_memory
Ceci est résolu dans la version Java 1.6.0_23 et vers le haut.
Voir plus de détails à http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935
Runtime.getRuntime().exec
alloue le processus avec la même quantité de mémoire que le principal. Si vous avez défini le tas sur 1 Go et essayez d'exec, il allouera un autre 1 Go pour que ce processus s'exécute.
Je suis tombé sur ces liens:
Http://mail.openjdk.java.net/pipermail/core-libs-dev/2009-May/001689.html
Http://www.nabble.com/Review-request-for-5049299-td23667680.html
Semble être un bug. L'utilisation d'une astuce spawn () au lieu de la fourchette simple()/exec() est conseillée.
J'ai résolu cela en utilisant 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");
}
}
Si vous regardez dans la source de java.lang.Runtime, vous verrez exec enfin appeler la méthode protégée: execVM, ce qui signifie qu'il utilise la mémoire virtuelle. Ainsi, pour un système de type Unix, la machine virtuelle dépend de la quantité d'espace d'échange + d'un certain ratio de mémoire physique.
La réponse de Michael a résolu votre problème mais elle pourrait (ou pour dire, finirait par) provoquer L'impasse O. S. dans le problème d'allocation de mémoire puisque 1 dire O. S. moins prudent de l'allocation de mémoire et 0 est juste deviner et évidemment que vous avez de la chance que O. s. je suppose que vous pouvez avoir de la mémoire cette fois. La prochaine fois? Hum.....
Une meilleure approche est que vous expérimentez votre cas et donnez un bon espace d'échange et donnez un meilleur ratio de mémoire physique utilisée et définissez la valeur sur 2 plutôt que 1 ou 0.
Overcommit_memory
Contrôle la surcommission de la mémoire système, permettant éventuellement aux processus d'allouer (mais pas d'utiliser) plus de mémoire que ce qui est réellement disponible.
0-gestion heuristique des surcommissions. Les surcommissions évidentes de l'espace d'adressage sont refusées. Utilisé pour un système typique. Il assure une allocation sérieusement sauvage échoue tout en permettant overcommit pour réduire l'utilisation de swap. root est autorisé à allouer légèrement plus de mémoire dans ce mode. C'est la valeur par défaut.
1-Toujours overcommit. Pour certaines applications scientifiques.
2-Ne pas surcharger. L'espace d'adressage total de validation pour le système n'est pas autorisé à dépasser swap plus un pourcentage configurable (par défaut est 50) de RAM physique. Selon le pourcentage que vous utilisez, dans la plupart des situations, cela signifie qu'un processus ne sera pas tué en essayant d'utiliser la mémoire déjà allouée, mais recevra des erreurs sur l'allocation de mémoire, le cas échéant.
Vous pouvez utiliser le wrapper Tanuki pour générer un processus avec POSIX spawn au lieu de fork. http://wrapper.tanukisoftware.com/doc/english/child-exec.html
Le WrapperManager.la fonction exec() est une alternative à Java-Runtime.exec() qui a l'inconvénient d'utiliser la méthode fork (), qui peut devenir sur certaines plates-formes très coûteuse en mémoire pour créer un nouveau processus.
Aussi étrange que cela puisse paraître, un travail consiste à réduire la quantité de mémoire allouée à la JVM. Puisque fork() duplique le processus et sa mémoire, si votre processus JVM n'a pas vraiment besoin de autant de mémoire que celle allouée via-Xmx, l'allocation de mémoire à git fonctionnera.
Bien sûr, vous pouvez essayer d'autres solutions mentionnées ici (comme la sur-Validation ou la mise à niveau vers une JVM qui a le correctif). Vous pouvez essayer de réduire la mémoire si vous êtes désespéré pour une solution qui garde tout logiciel intact sans impact sur l'environnement. Gardez également à l'esprit que reducing-Xmx agressivement peut causer des OOMs. Je recommande la mise à niveau du JDK en tant que solution stable à long terme.