2012-01-12 68 views
11

我知道這個問題已經存在了至少3年(Issue 92),但我仍然不滿意它的當前狀態。我也知道,如果在重新部署後重新啓動(如Guice + Tomcat potential memory leak中所建議的),則這不會影響Tomcat。Guice 3.0 + Tomcat 7.0 = ClassLoader內存泄漏

我的問題是我在部分重新部署後遇到OutOfMemoryError: PermGen錯誤。請注意,我沒有明確使用google-collections,我只使用Guice 3.0(通過maven)。分析堆轉儲後,我仍然看到線程com.google.inject.internal.Finalizer仍處於活動狀態,並保留對Tomcat的WebappClassLoader的引用,從而阻止垃圾回收。

如果我實際上需要重新部署,而不重新啓動並且正在使用Guice?我有什麼選擇?

回答

9

好了,沒有人在那裏幫助我,所以這裏我學到了什麼:

終結器線程由FinalizableReferenceQueue(FRQ)開始。 MapMaker中FRQ有一個很難(靜態的)引用。 WebAppClassLoader沒有被垃圾收集,因爲MapMaper仍然是由於硬引用。

下面的代碼解決我的問題:

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); 

這裏的違規代碼(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(); 
} 

這樣做後,終結器線程正常死亡。

+0

以下是此問題的錯誤報告:http://code.google.com/p/google-guice/issues/detail?id=288 – Gili 2012-01-24 01:41:27