Sun 的 Java SSL 实现正在泄漏内存?

2022-09-04 21:16:26

我有一个服务器组件,我正在尝试进行负载测试。与服务器的所有连接都使用 TLS 1.0。我有一个简单的测试程序,基本上可以在我想要的任意数量的线程上执行此操作:

Full TLS handshake to the server
send a request
read reply
close connection
repeat ad nauseam

我的虚拟机如下所示:

Java(TM) SE Runtime Environment (build 1.6.0_16-b01)
Java HotSpot(TM) Server VM (build 14.2-b01, mixed mode)

我有一个内存泄漏。当我对服务器进行大量测试时,我的内存占用量每秒增加约1兆克,这使得它在15-20分钟后被阻止。OutOfMemoryException

我在 Netbean 的分析器中运行了它,它表明内存的增加是在 TLS API 的深处。

有没有人经历过类似的事情?是否有任何解决方法可以在我的级别实施?

编辑。根据要求,下面是性能分析调用跟踪,它生成了很多这样的字节[]:

.java.io.ByteArrayOutputStream.<init>(int)
..com.sun.net.ssl.internal.ssl.OutputRecord.<init>(byte, int)
...com.sun.net.ssl.internal.ssl.OutputRecord.<init>(byte)
....com.sun.net.ssl.internal.ssl.AppOutputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl)
.....com.sun.net.ssl.internal.ssl.SSLSocketImpl.init(com.sun.net.ssl.internal.ssl.SSLContextImpl, boolean)
......com.sun.net.ssl.internal.ssl.SSLSocketImpl.<init>(com.sun.net.ssl.internal.ssl.SSLContextImpl, java.net.Socket, String, int, boolean)
.......com.sun.net.ssl.internal.ssl.SSLSocketFactoryImpl.createSocket(java.net.Socket, String, int, boolean)
<my code>

我还可以放更多...这将是很长的。我会告诉你探查器给我的入口点:

....com.sun.net.ssl.internal.ssl.AppOutputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl)
....com.sun.net.ssl.internal.ssl.HandshakeOutStream.<init>(com.sun.net.ssl.internal.ssl.ProtocolVersion, com.sun.net.ssl.internal.ssl.ProtocolVersion, com.sun.net.ssl.internal.ssl.HandshakeHash, com.sun.net.ssl.internal.ssl.SSLSocketImpl)
....com.sun.net.ssl.internal.ssl.SSLSocketImpl.sendAlert(byte, byte)
..com.sun.net.ssl.internal.ssl.AppInputStream.<init>(com.sun.net.ssl.internal.ssl.SSLSocketImpl)
..com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake()
..com.sun.net.ssl.internal.ssl.HandshakeInStream.<init>(com.sun.net.ssl.internal.ssl.HandshakeHash)

答案 1

所有 SSL 连接都与 SSL 会话相关联,该会话可以在不同的 TCP 连接中重复使用,以减少在建立实际 TCP 连接后协商临时加密密钥时的握手开销。可能是您的客户端以某种方式强制创建新会话,并且由于Java 6的默认配置似乎是在一小时内缓存无限数量的会话,因此您可能很容易遇到内存问题。

您可以通过使用 getSession().getSessionContext() 从服务器套接字中获取 SSLSessionContext 来操作服务器套接字的这些设置,并使用 setSessionCacheSize 设置缓存大小,并使用 setSessionTimeout 设置超时(以秒为单位)。我本来希望可以通过系统属性更改默认配置,但我找不到任何有关此的文档。也许你可以通过谷歌搜索自己找到一些东西,比我更长一点。


是否确定要对正确的会话上下文设置限制?我错误地认为可以从服务器套接字访问上下文。在创建服务器套接字之前,您必须通过 SSLContext 进行设置:

SSLContext sslContext = SSLContext.getDefault();
sslContext.getServerSessionContext().setSessionCacheSize(1000);
SSLServerSocket ss = (SSLServerSocket)
     sslContext.getServerSocketFactory().createServerSocket(<port>);

如果没有此限制,很容易重现内存“泄漏”,因为每个缓存的SSL会话接缝都使用大约7-800字节的堆内存。由于会话计数限制,我的服务器现在已在压力下运行了大约 15 分钟,并且仍然仅使用 3-4 MB 的堆内存。


答案 2

你已经看到连接关闭了。最有可能的是,这仍然以某种方式开放。1Mb是一些额外线程的歌声。但是,我不确定究竟是什么原因。


推荐