¿Cómo lidiar con "java.lang.OutOfMemoryError: Java heap space" error?

Estoy escribiendo una aplicación del lado del cliente Swing (diseñador gráfico de fuentes) en Java 5. Recientemente, estoy corriendo en java.lang.OutOfMemoryError: Java heap space error porque no estoy siendo conservador en el uso de la memoria. El usuario puede abrir un número ilimitado de archivos, y el programa mantiene los objetos abiertos en la memoria. Después de una rápida investigación he encontrado Ergonomía en la máquina virtual Java 5.0 y otros que dicen que en una máquina Windows la JVM tiene por defecto un tamaño máximo de heap de 64MB.

Teniendo en cuenta esta situación, ¿cómo debo lidiar con esta restricción?

Podría aumentar el tamaño máximo de la pila utilizando la opción de línea de comandos de java, pero eso requeriría averiguar la RAM disponible y escribir algún programa o script de lanzamiento. Además, aumentar el tamaño a un máximo infinito no elimina el problema.

Podría reescribir parte de mi código para persistir los objetos en el sistema de archivos con frecuencia (usar la base de datos es lo mismo) para liberar la memoria. Podría funcionar, pero probablemente sea mucho trabajo también.

Si puedes indicarme los detalles de las ideas anteriores o algunas alternativas como memoria virtual automática, ampliando el tamaño del heap dinámicamente, sería genial.

Solución

En última instancia, siempre se tiene un máximo finito de heap para usar, independientemente de la plataforma en la que se esté ejecutando. En Windows 32 bits esto es alrededor de 2GB (no específicamente el heap sino la cantidad total de memoria por proceso). Lo que pasa es que Java elige hacer el máximo por defecto más pequeño (presumiblemente para que el programador no pueda crear programas que tengan una asignación de memoria desbocada sin encontrarse con este problema y tener que examinar exactamente lo que están haciendo).

Así que esto dado que hay varios enfoques que podría tomar para determinar la cantidad de memoria que necesita o para reducir la cantidad de memoria que está utilizando. Un error común con lenguajes de recolección de basura como Java o C# es mantener alrededor referencias a objetos que ya no estás usando, o asignar muchos objetos cuando podrías reutilizarlos en su lugar. Mientras los objetos tengan una referencia a ellos, seguirán utilizando espacio de la pila, ya que el recolector de basura no los borrará.

En este caso puedes utilizar un perfilador de memoria de Java para determinar qué métodos de tu programa están asignando un gran número de objetos y luego determinar si hay una manera de asegurarse de que ya no son referenciados, o de no asignarlos en primer lugar. Una opción que he utilizado en el pasado es "JMP" .

Si determinas que estás asignando estos objetos por una razón y necesitas mantener alrededor de las referencias (dependiendo de lo que estés haciendo este podría ser el caso), sólo tendrás que aumentar el tamaño máximo del heap cuando inicies el programa. Sin embargo, una vez que hagas el perfil de memoria y entiendas cómo se están asignando tus objetos deberías tener una mejor idea de cuánta memoria necesitas.

En general, si no puedes garantizar que tu programa se ejecutará en una cantidad finita de memoria (quizás dependiendo del tamaño de la entrada) siempre te encontrarás con este problema. Sólo después de agotar todo esto necesitarás buscar el almacenamiento en caché de los objetos en el disco, etc. En este punto deberías tener una muy buena razón para decir "Necesito Xgb de memoria" para algo y no puedes' solucionarlo mejorando tus algoritmos o patrones de asignación de memoria. Por lo general, esto sólo suele ser el caso de los algoritmos que operan en grandes conjuntos de datos (como una base de datos o algún programa de análisis científico) y entonces técnicas como el almacenamiento en caché y el IO mapeado en memoria se vuelven útiles.

Comentarios (1)

Ejecute Java con la opción de línea de comandos -Xmx, que establece el tamaño máximo del montón.

(Véase aquí para más detalles) (http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java.html#nonstandard).

Comentarios (3)

Sí, con -Xmx puede configurar más memoria para su JVM. Para estar seguro de que no hay fugas o desperdicio de memoria. Haz un volcado de heap y utiliza el analizador de memoria de Eclipse para analizar tu consumo de memoria.

Comentarios (1)