Cómo resolver “java.io.IOException: error = 12, No se puede asignar memoria” llamando a Runtime # exec ()?

En mi sistema, no puedo ejecutar una simple aplicación Java que inicie un proceso. No sé cómo resolverlo.

¿Podrías darme algunas pistas sobre cómo resolverlo?

El progtwig es:

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

El resultado es:

 [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 

Configuración 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) 

EDITAR: Solución Esto resuelve mi problema, no sé exactamente por qué:

echo 0> / proc / sys / vm / overcommit_memory

Votos ascendentes para quién es capaz de explicar 🙂

Informaciones adicionales, salida superior:

 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 

Informaciones adicionales, salida 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 

¿Cuál es el perfil de memoria de su máquina? por ejemplo, si ejecuta top , ¿cuánta memoria libre tiene?

Sospecho que UnixProcess realiza una fork() y simplemente no está obteniendo suficiente memoria del sistema operativo (si la memoria le sirve, fork() duplicar el proceso y luego ejecutar exec() ejecutar la l en el nuevo proceso de memoria, y es no llegar tan lejos como eso)

EDITAR: Re. su solución de compromiso, permite la sobrecomisión de la memoria del sistema, posiblemente permitiendo que los procesos asignen (pero no usen) más memoria de la que realmente está disponible. Así que supongo que fork() duplica la memoria de proceso de Java como se explica en los comentarios a continuación. Por supuesto, no utiliza la memoria ya que ‘ls’ reemplaza el proceso duplicado de Java.

Esta es la solución, pero tienes que establecer:

 echo 1 > /proc/sys/vm/overcommit_memory 

Esto se resuelve en la versión de Java 1.6.0_23 y en adelante.

Vea más detalles en http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=7034935

Runtime.getRuntime().exec asigna el proceso con la misma cantidad de memoria que la principal. Si hiciste un montón de 1 GB y tratas de ejecutar, asignará otro 1GB para que se ejecute ese proceso.

Encontré estos enlaces:

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

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

Parece ser un error. Se recomienda el uso de un truco de spawn () en lugar del tenedor simple () / exec ().

Lo solucioné usando 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 nos fijamos en el origen de java.lang.Runtime, verá que exec finalmente llamará al método protegido: execVM, lo que significa que utiliza la memoria virtual. Entonces, para un sistema tipo Unix, la VM depende de la cantidad de espacio de intercambio + alguna proporción de memoria física.

La respuesta de Michael resolvió tu problema, pero podría (o decir, eventualmente) causar un locking del sistema operativo en cuestión de asignación de memoria, ya que 1 indica al sistema operativo menos cuidado de asignación de memoria y 0 simplemente adivina y obviamente tienes suerte de que el SO adivine que puedes tener memoria ESTA VEZ. ¿La próxima vez? Hmm …..

Un mejor enfoque es que experimente su caso y le dé un buen espacio de intercambio y proporcione una mejor proporción de memoria física utilizada y establezca el valor en 2 en lugar de 1 o 0.

overcommit_memory

Controla la sobrecarga de la memoria del sistema, posiblemente permitiendo que los procesos asignen (pero no usen) más memoria de la que realmente está disponible.

0 – Manejo excesivo heurístico. Los sobrecompisos obvios de espacio de direcciones son rechazados. Usado para un sistema típico. Asegura que una asignación seriamente salvaje falla al tiempo que permite un compromiso excesivo para reducir el uso de intercambio. root tiene permitido asignar un poco más de memoria en este modo. Este es el predeterminado.

1 – Siempre exceso de compromiso. Apropiado para algunas aplicaciones científicas.

2 – No se comprometa demasiado. No se permite que la confirmación total del espacio de direcciones para el sistema exceda el intercambio más un porcentaje configurable (por defecto es 50) de RAM física. Dependiendo del porcentaje que use, en la mayoría de las situaciones esto significa que un proceso no se eliminará mientras se intenta usar la memoria ya asignada, pero recibirá errores en la asignación de memoria según corresponda.

Puedes usar el contenedor Tanuki para generar un proceso con POSIX spawn en lugar de fork. http://wrapper.tanukisoftware.com/doc/english/child-exec.html

La función WrapperManager.exec () es una alternativa a Java-Runtime.exec () que tiene la desventaja de utilizar el método fork (), que puede convertirse en algunas plataformas muy costosas en memoria para crear un nuevo proceso.

Aunque suene extraño, una solución alternativa es reducir la cantidad de memoria asignada a la JVM. Como fork () duplica el proceso y su memoria, si su proceso de JVM no necesita tanta memoria como se asigna a través de -Xmx, la asignación de memoria a git funcionará.

Por supuesto, puede probar otras soluciones que se mencionan aquí (como el exceso de compromiso o la actualización a una JVM que tenga la solución). Puede intentar reducir la memoria si está desesperado por una solución que mantenga intacto todo el software sin impacto en el entorno. También tenga en cuenta que reducir -Xmx agresivamente puede causar OOM. Recomiendo actualizar el JDK como una solución estable a largo plazo.