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

有没有办法解决缓存组件中的Google Guava r15 内存泄漏 (链接到错误报告) ?

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

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

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

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

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

编辑

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

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

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

编辑2和3

我想这样做是安全的

 Stripped64.threadHashCode = new ThreadHashCode(); 

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

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

另一件可能或不可行的事情是我在问题页面上提出的建议。 这只是一个20行补丁。 或者只是等待,问题已经分配到昨天。

编辑4

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

编辑5

看起来它最终会被修复。 从问题 :

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

乍一看, 他的变化似乎与我的相同。

编辑6

最后,这已经被标记为固定,并且已经宣布了Guava 18.0-rc1 。 考虑到变化与我的变化(9个月前)相同,只花了很长时间。

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

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

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