关键的番石榴内存泄漏 - 需要解决方法

时间:2013-10-28 18:45:34

标签: java web-applications memory-leaks guava

有没有办法解决缓存组件中的Google Guava r15 memory leak (link to the bug report)

(不依赖于应用程序服务器可能会清理和/或考虑永远不会重新启动/重新部署Web应用程序)

3 个答案:

答案 0 :(得分:11)

我想你不需要关心它。 Tomcat消息说

  

线程会随着时间的推移而更新,以避免可能的内存泄漏。

IIUIC意味着一旦所有旧线程都消失了,所有指向旧版本的指针的指针也将消失。

详细信息:线程池的原因是线程创建的巨大成本。池化本身是hacky,因为你得到一个正在做其他事情的线程,而线程不是无状态的。假设您需要很多线程并且从不回收它们,线程创建是昂贵的。每隔几分钟更新所有线程没有任何问题,所以我希望,Tomcat的解决方法能够完美地解决它。 但事实并非如此。

修改

我害怕,我误会了什么。链接的错误说

  

使用番石榴缓存的Web应用程序似乎可能面临内存泄漏。   在多次重新部署之后,应用程序容器因OutOfMemoryError崩溃或停止。

我认为Tomcat可以很容易地解决它,但无论出于什么原因它都没有。所以我很害怕,你必须自己清理ThreadLocal。通过反射很容易实现,相关字段为Thread.threadLocals,可能为inheritableThreadLocals。这是一个糟糕的黑客,更难的部分是当没有任何错误时,即没有加载任何应用程序时实现这一点。

编辑2和3

我认为做

之类的事情是安全的
Stripped64.threadHashCode = new ThreadHashCode();

因为所包含的内容仅在重大争用下才能获得性能,并且在使用时会重新创建。 但根据MRalwasser的评论,它根本无济于事,因为活着的线程仍会引用旧值。所以似乎没办法。

由于ThreadLocal通过使用线程存储数据(而不是使用真实的Map<Thread, Something>)来工作,所以您必须通过所有线程并删除那里的引用。愚弄其他线程的私有字段是一个可怕的想法,因为它们不是线程安全的,也是由于可见性问题。

另一件可能或不可行的事情是我对issue page的建议。这只是一个20行补丁。或者只是等一下,问题已于昨天分配。

编辑4

未使用的线程本地不会导致任何问题。 AFAIK唯一使用此TL的是缓存统计信息。因此,请避免同时CacheBuilder.recordStatsCache.statsStripped64加载。

编辑5

看起来它最终会被修复。来自issue

  Doug为我们修复了这个问题,我们将它修补回了番石榴:   http://gee.cs.oswego.edu/cgi-bin/viewcvs.cgi/jsr166/src/jsr166e/Striped64.java?revision=1.9

乍一看his change似乎与mine相同。

编辑6

最后,这已被标记为已修复,Guava 18.0-rc1已宣布。考虑到变化与我的变化(9个月前)相同,这很长很难过。

答案 1 :(得分:2)

您可以使用ServletListener ClassLoaderLeakPreventor https://github.com/mjiderhamn/classloader-leak-prevention/,它还会在取消部署/停止时清除ThreadLocals。它还有其他常见泄漏的修复/解决方法。

答案 2 :(得分:0)

似乎是ThreadLocals的缺点。每次在ThreadLocal中放置应用程序级别时,都会得到相同的结果。

唯一的解决方法是在部署时重新启动服务器。我认为这是Java应用程序的一个已知问题。你确定它是唯一一个停止卸载类加载器的地方吗?