Guice 3.0 + Tomcat 7.0 = ClassLoader内存泄漏 [英] Guice 3.0 + Tomcat 7.0 = ClassLoader memory leak

查看:122
本文介绍了Guice 3.0 + Tomcat 7.0 = ClassLoader内存泄漏的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我知道这个问题已经存在至少3年了( Issue 92 ),但我仍然不满意当前的状态。我也知道如果重新部署后重新启动,这不会影响Tomcat(如 Guice +中所述) Tomcat潜在的内存泄漏)。



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

如果我实际上需要重新部署而不重新启动并使用Guice会怎样?我有什么选择?

解决方案

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



Finalizer线程由FinalizableReferenceQueue(FRQ)启动。 MapMaker中有一个对FRQ的硬(静态)引用。 WebAppClassLoader没有被垃圾收集,因为由于硬参考,MapMaper仍然存在。



以下代码解决我的问题:

  final Class<?> queueHolderClass = 
Class.forName(com.google.inject.internal.util。$ MapMaker $ QueueHolder);
final字段queueField = queueHolderClass.getDeclaredField(queue);
//使MapMaker.QueueHolder.queue可访问
queueField.setAccessible(true);
//从MapMaker.QueueHolder.queue中移除最终修饰符
final Field modifiersField = Field.class.getDeclaredField(modifiers);
modifiersField.setAccessible(true);
modifiersField.setInt(queueField,queueField.getModifiers()& ~Modifier.FINAL);
//将其设置为null
queueField.set(null,null);

以下是违规代码( com.google .inject.internal.util.MapMaker ):

  / **包装类确保队列不存在直到它被使用才被创造。 * / 
私有静态类QueueHolder {
静态final finalizableReferenceQueue queue = new FinalizableReferenceQueue();
}

执行此操作后,Finalizer线程会正常死亡。


I know that this problem has been around for at least 3 yeears (Issue 92), but I'm still not satisfied with the current state of it. I am also aware that this does not affect Tomcat if you do restart after redeploying (as suggested in Guice + Tomcat potential memory leak).

My problem is that I am experiencing OutOfMemoryError: PermGen errors after some redeployments. Notice that I am not using google-collections explicitly, I am only using Guice 3.0 (via maven). After analyzing heap dumps, I still see that the thread com.google.inject.internal.Finalizer is still active, keeps a reference to Tomcat's WebappClassLoader, thus hindering garbage collection.

What if I actually require redeployments without restarting and am using Guice? What are my options?

解决方案

Well, no one was there to help me, so here's what I learned:

The Finalizer thread is started by the FinalizableReferenceQueue (FRQ). There is a hard (static) reference to the FRQ in MapMaker. The WebAppClassLoader was not garbage collected because MapMaper was still around due to the hard reference.

The following code solved my problem:

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

Here's the offending code (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();
}

After doing this, the Finalizer thread gracefully dies.

这篇关于Guice 3.0 + Tomcat 7.0 = ClassLoader内存泄漏的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆