我有一个在Amazon EC2上运行的应用程序(使用多种AWS产品,如S3,DynamoDB等),并且内存泄漏。我收集了一些堆转储并通过Eclipse的内存分析器工具运行它们,该工具将sun.security.ssl.SSLSocketImpl
(占用数十MB内存)的数百个实例确定为可能的泄漏。
我无法弄清楚为什么这些SSLSocketImpl
物品没有被处理掉。
转储中SSLSocketImpl
的大多数实例都有两个引用,一个来自java.lang.ref.Finalizer
,另一个来自com.amazonaws.internal.SdkSSLSocket
。我的堆转储中的Finalizer线程报告为空闲,没有任何对象等待完成。但是,引用泄漏的com.amazonaws.internal.SdkSSLSocket
对象的SSLSocketImpl
对象似乎已被清除。至少,我无法在堆转储中找到它们(MAT中的Dominator视图)。
我是分析Java堆转储的新手。我接下来应该寻找什么?如果确实清理了亚马逊SdkSSLSocket
对象,为什么SSLSocketImpl
对象也没有被清除?
谢谢!
答案 0 :(得分:2)
我想我也遇到了这个问题。在与MAT纠缠了一点之后,我能够找到原因,或者至少阻止了G1GC在保有权空间上进行完整的GC。这是我正在查看的垫图:
我的应用程序是一个简单的Spring Boot反应式http服务器,它代理了相当数量的数据库读取调用。我在带有约4GB内存的K8s上的docker容器中运行单个CPU。我将其增加了一倍,达到8GB的内存,仍然发现了问题。
我不认为这是内存泄漏,因为我可以看到完整的GC能够清理需要一段时间的永久性空间。
我认为JDBC在做的事情是TCP连接被放弃,它们被降级到名为 AbandonedConnectionCleanupThread 的线程。
So what the solution turned out to be was just giving the JVM an extra CPU to service the AbandonedConnectionCleanupThread
。
这样做之后,我的保有空间大小就永远不会增长,并且g1_old_space会以保有空间的大小增长,但是我的G1能够比保有空间更有效地清理g1_old_space,因此长时间的应用程序暂停消失了,G1尊重我的< strong> -XX:MaxGCPauseMillis
答案 1 :(得分:1)
这可能是因为未设置SSL会话缓存大小,默认情况下该缓存大小是无限的,最终可能会消耗大量的堆空间。设置javax.net.ssl.sessionCacheSize = 1000应该会有所帮助。