2012-01-12 3 views
11

So che questo problema è in circolazione da almeno 3 anni (Issue 92), ma non sono ancora soddisfatto dello stato corrente. Sono anche consapevole del fatto che ciò non influisce su Tomcat se si riavvia dopo la ridistribuzione (come suggerito in Guice + Tomcat potential memory leak).Guice 3.0 + Tomcat 7.0 = Perdita di memoria ClassLoader

Il mio problema è che si verificano errori OutOfMemoryError: PermGen dopo alcune ridistribuzioni. Si noti che non sto utilizzando google-collections in modo esplicito, sto solo usando Guice 3.0 (via Maven). Dopo aver analizzato i dump dell'heap, vedo ancora che il thread com.google.inject.internal.Finalizer è ancora attivo, mantiene un riferimento a WebappClassLoader di Tomcat, impedendo così la raccolta dei dati inutili.

Cosa succede se Irichiede effettivamente le ridistribuzioni senza riavviare e sto utilizzando Guice? Quali sono le mie opzioni?

risposta

9

Beh, non c'era nessuno ad aiutarmi, quindi ecco quello che ho imparato:

Il filo Finalizer viene avviata dal FinalizableReferenceQueue (FRQ). C'è un riferimento (fisso) difficile all'FRQ in MapMaker. Il WebAppClassLoader non è stato sottoposto a garbage collection perché MapMaper era ancora in circolazione a causa del difficile riferimento.

Il seguente codice di risolto il mio 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); 

Ecco il codice diincriminato (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(); 
} 

Dopo aver fatto questo, il filo Finalizer muore con grazia.

+0

Ecco la segnalazione di bug relativa a questo problema: http://code.google.com/p/google-guice/issues/detail?id=288 – Gili