我知道这个问题已经存在至少3年了(第92期),但是我仍然不满意它的当前状态。我还知道,如果您在重新部署后重新启动,这不会影响Tomcat(如Guice +Tomcat潜在的内存泄漏所述)。
我的问题是OutOfMemoryError: PermGen重新部署后遇到错误。请注意,我没有显式使用google- collections,而是仅使用Guice 3.0(通过Maven)。在分析堆转储之后,我仍然看到该线程com.google.inject.internal.Finalizer仍处于活动状态,并保留了对Tomcat的WebappClassLoader的引用,从而阻碍了垃圾回收。
OutOfMemoryError: PermGen
com.google.inject.internal.Finalizer
如果我 实际上需要 重新部署而不重新启动并且正在使用Guice,该怎么办?我有什么选择?
好吧,没有人在那里帮助我,所以这是我学到的东西:
终结器线程由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):
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(); }
完成此操作后,终结器线程正常退出。