【问题标题】:Guice 3.0 + Tomcat 7.0 = ClassLoader memory leakGuice 3.0 + Tomcat 7.0 = ClassLoader 内存泄漏
【发布时间】:2012-02-09 03:58:33
【问题描述】:

我知道这个问题已经存在了至少 3 年 (Issue 92),但我仍然对它的当前状态不满意。我也知道,如果您在重新部署后重新启动(如Guice + Tomcat potential memory leak 中所建议的那样),这不会影响 Tomcat。

我的问题是我在重新部署后遇到了OutOfMemoryError: PermGen 错误。请注意,我没有明确使用 google-collections,我只使用 Guice 3.0(通过 maven)。分析堆转储后,我仍然看到线程com.google.inject.internal.Finalizer 仍然处于活动状态,保持对Tomcat 的WebappClassLoader 的引用,从而阻碍了垃圾回收。

如果我实际上需要重新部署而不重新启动并且正在使用 Guice,该怎么办?我有哪些选择?

【问题讨论】:

    标签: java tomcat memory-leaks guice


    【解决方案1】:

    好吧,没有人可以帮助我,所以这是我学到的:

    Finalizer 线程由 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();
    }
    

    完成此操作后,Finalizer 线程优雅地终止。

    【讨论】:

    猜你喜欢
    • 2012-08-06
    • 2012-04-09
    • 2014-08-05
    • 2012-12-06
    • 2014-12-25
    • 2014-04-05
    • 2015-12-27
    • 1970-01-01
    相关资源
    最近更新 更多