2012-01-12 15 views
11

Sé que este problema ha existido durante al menos 3 años (Issue 92), pero todavía no estoy satisfecho con el estado actual de la misma. También soy consciente de que esto no afecta a Tomcat si lo reinicias después de volver a implementarlo (como se sugiere en Guice + Tomcat potential memory leak).Guice 3.0 + Tomcat 7.0 = pérdida de memoria ClassLoader

Mi problema es que estoy experimentando errores OutOfMemoryError: PermGen después de algunas reordenaciones. Tenga en cuenta que no estoy usando google-collections explícitamente, solo estoy usando Guice 3.0 (via maven). Después de analizar volcados de almacenamiento dinámico, todavía veo que el hilo com.google.inject.internal.Finalizer aún está activo, guarda una referencia al WebappClassLoader de Tomcat, lo que dificulta la recolección de basura.

¿Qué pasa si I realmente requiere redistribuciones sin reiniciar y estoy usando Guice? ¿Cuáles son mis opciones?

Respuesta

9

Bueno, nadie estaba allí para ayudar, así que esto es lo que aprendí:

El subproceso finalizador es iniciado por el FinalizableReferenceQueue (FRQ). Hay una referencia dura (estática) al FRQ en MapMaker. El WebAppClassLoader no se recolectó como basura porque MapMaper todavía estaba presente debido a la referencia difícil.

El siguiente código resuelto mi problema:

final Class<?> queueHolderClass = 
    Class.forName("com.google.inject.internal.util.$MapMaker$QueueHolder"); 
final Field queueField = queueHolderClass.getDeclaredField("queue"); 
// make MapMaker.QueueHolder.queue accessible 
queueField.setAccessible(true); 
// remove the final modifier from MapMaker.QueueHolder.queue 
final Field modifiersField = Field.class.getDeclaredField("modifiers"); 
modifiersField.setAccessible(true); 
modifiersField.setInt(queueField, queueField.getModifiers() & ~Modifier.FINAL); 
// set it to null 
queueField.set(null, null); 

Aquí está el código deinfractor (com.google.inject.internal.util.MapMaker):

/** Wrapper class ensures that queue isn't created until it's used. */ 
private static class QueueHolder { 
    static final FinalizableReferenceQueue queue = new FinalizableReferenceQueue(); 
} 

Después de hacer esto, el subproceso finalizador con gracia muere.

+0

Aquí está el informe de error para este problema: http://code.google.com/p/google-guice/issues/detail?id=288 – Gili

Cuestiones relacionadas