Pregunta

Hemos bajado nuestra instancia de pez de vidrio cada dos semanas por un tiempo con un java.lang.OutOfMemoryError: PermGen space. Aumenté el espacio de Permgen a 512 MB y el uso de la memoria de descarga de startet con jstat -gc. Después de dos semanas, se me ocurrió el siguiente gráfico que muestra cómo el espacio de Permgen aumenta constantemente (las unidades en el eje X son minutos, el eje Y es KB).Graph of increasing PermGen usage

Intenté buscar en Google algún tipo de herramienta de perfil que podría identificar el error y un hilo aquí en JMAP así mencionado, lo que resultó ser bastante útil. De las aproximadamente 14000 líneas arrojadas desde jmap -permstats $PID, aproximadamente 12500 contenidos groovy/lang/GroovyClassLoader$InnerLoader, señalando algún tipo de fuga de memoria de nuestro propio código Groovy o Groovy. Tengo que señalar que Groovy constituye menos del 1% de la base de código relevante.

Ejemplo de salida a continuación:

class_loader    classes bytes   parent_loader   alive?  type

<bootstrap> 3811    14830264      null      live    <internal>
0x00007f3aa7e19d20  20  164168  0x00007f3a9607f010  dead    groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa7c850d0  20  164168  0x00007f3a9607f010  dead    groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aa5d15128  21  181072  0x00007f3a9607f010  dead    groovy/lang/GroovyClassLoader$InnerLoader@0x00007f3a7afb4120
0x00007f3aad0b40e8  36  189816  0x00007f3a9d31fbf8  dead    org/apache/jasper/servlet/JasperLoader@0x00007f3a7d0caf00
....

Entonces, ¿cómo puedo proceder a obtener más información sobre qué código está causando esto?

De Este artículo Infiero que nuestro código maravilloso está creando dinámicamente clases en alguna parte. Y desde el vertedero de JMAP puedo ver que la mayoría de los objetos/clases muertos (?) Tienen el mismo parent_loader, aunque no estoy seguro de lo que eso significa en este contexto. No sé cómo proceder desde aquí.

Apéndice

Para los recién llegados, vale la pena señalar que el La respuesta aceptada no soluciona el problema. Simplemente extiende el período necesario antes de reiniciarse con un diez veces al no almacenar tanta información de clase. Lo que realmente solucionó nuestros problemas fue deshacerse del código que lo generó. Utilizamos el marco de validación (diseño por contrato) Oval Donde se podría escribir limitaciones personalizadas usando Groovy como anotaciones en métodos y clases. Eliminar las anotaciones a favor de las condiciones previas y posteriores a las condiciones en Java era aburrida, pero hizo el trabajo. Sospecho que cada vez que se revisaba una restricción ovalada, se estaba creando una nueva clase anónima y de alguna manera los datos de la clase asociados estaban causando una fuga de memoria.

¿Fue útil?

Solución

Tuvimos un problema similar (1 semana entre accidentes). El problema parece ser que Groovy almacena meta métodos. Terminamos usando este código basado en esta discusión y informe de error

GroovyClassLoader loader = new GroovyClassLoader();
Reader reader = new BufferedReader(clob.getCharacterStream());
GroovyCodeSource source = new GroovyCodeSource(reader, name, "xb3.Classifier");
Class<?> groovyClass = loader.parseClass(source);
Object possibleClass = groovyClass.newInstance();
if (expectedType.isAssignableFrom(possibleClass.getClass())) {
    classifiers.put((T) possibleClass, name);
}
reader.close();
// Tell Groovy we don't need any meta
// information about these classes
GroovySystem.getMetaClassRegistry().removeMetaClass(possibleClass.getClass());
// Tell the loader to clear out it's cache,
// this ensures the classes will be GC'd
loader.clearCache();

Otros consejos

Si estás usando Sun JVM, cámbielo para IBM JVM, funcionará bien, espero :)

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top