未终结的物体耗尽记忆力

时间:2015-02-24 17:37:25

标签: java garbage-collection finalizer

我们在AWS上的Tomcat中以大约20个实例的形式运行基于Jersey(1.x)的服务定期一个实例"变坏":在大约4小时的过程中堆和CPU使用量增加,直到堆耗尽并且CPU被固定。此时它会自动从负载均衡器中移除并最终被杀死。

检查来自这些实例的堆转储,大约95%的内存已经被java.lang.ref.Finalizer的实例用完了,这个实例持有各种东西,但大多数或全部都与HTTPS有关connections sun.net.www.protocol.https.HttpsURLConnectionImpl,sun.security.ssl.SSLSocketImpl,各种加密对象)。这些是我们使用Jersey的客户端库对外部Web服务进行的连接。来自"健康"的堆转储实例并不表示任何问题。

在相对较低的负载情况下运行数天或数周没有问题。随着负载的增加,实例失败的频率也会增加(平均CPU达到每天几次~40%)。

我们的JVM args是:

-XX:+UseG1GC -XX:MaxPermSize=256m -Xmx1024m -Xms1024m

我正在为垃圾收集指标添加JMX日志记录,但我并不完全清楚我应该寻找什么。在这一点上,我主要是在寻找能够引发这种失败或其他调查目标的想法。

3 个答案:

答案 0 :(得分:0)

是否可能是连接泄漏?我假设你已经检查过了吗?

我遇到了类似GC错误的问题。根据您的JVM版本看起来您正在使用实验(并且可能有错误)功能。您可以尝试禁用G1并使用默认垃圾收集器。另外,根据您的版本,您可能会遇到垃圾收集开销,并且没有正确的GC内容,因为计算可以和不可以删除的内容需要很长时间。如果JVM中有-XX:-UseGCOverheadLimit可能会有所帮助。

答案 1 :(得分:0)

Java使用单个终结器线程来清理死对象。您的机器的症状与积压的最终确定一致。如果终结器线程减慢太多(因为某些对象需要很长时间才能完成),结果化的终结器队列条目的累积可能导致终结器线程进一步落后于传入的对象,直到一切都停止为止。

您可能会发现分析有助于确定哪些对象减慢了终结器线程。

答案 2 :(得分:0)

最终结果是由JVM错误导致的(不幸的是我丢失了与我们追踪到的特定链接的链接)。升级到较新版本的OpenJDK(我们最终使用OpenJDK 1.7.0_50)解决了这个问题,而我们没有对代码进行任何更改。