【问题标题】:Sun's Java SSL Implementation is Leaking Memory?Sun 的 Java SSL 实现正在泄漏内存?
【发布时间】:2009-10-26 08:34:50
【问题描述】:

我有一个服务器组件,我正在尝试进行负载测试。与服务器的所有连接都使用 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 兆,这使它在使用 OutOfMemoryException 15-20 分钟后阻塞。

我在 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)

【问题讨论】:

  • 你能提供一些更具体的分析结果吗?泄漏不一定来自 TLS,它可能在您的代码中。
  • 请创建表现出这种行为的最小可能程序并将其添加到您的问题中。

标签: java memory-leaks ssl


【解决方案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 的堆内存。

【讨论】:

  • 我设置了 1000 个会话的限制。坠机前的曲线不像以前那么陡峭(现在看起来像一个楼梯),所以这很有帮助。尽管如此,它仍然崩溃。
  • 86400sec 是默认超时时间(即 24 小时),您可以设置默认缓存大小:w/ -Djavax.net.ssl.sessionCacheSize=xxx 属性
【解决方案2】:

你看到连接关闭了吗?很可能这仍然以某种方式打开。 1Mb 是一些额外线程的歌声。但是,我不确定到底是什么原因。

【讨论】:

  • 我看过了。我正在使用Executors.newScheduledThreadPool,因此我无法完全控制在任何给定时间运行的线程数。话虽如此,分析器结果显示大部分内存都被 byte[] 占用。
  • 我将仔细检查客户端断开连接是否得到正确处理并且连接已关闭。好主意。
  • 是的,这有很大的不同!即使检测到断开连接(通过捕获 IOException),我也没有关闭 SSLSocket...
【解决方案3】:

1MB 是创建线程所需的内存,无论是否额外。

该类或包的错误列表中是否有任何条目?第一步是检查它。

第二步是假设问题出在你的代码上,而不是 Sun 的东西。更有可能,仅仅是因为 Java JDK 中的一个常用类已经被全世界的用户猛烈抨击。如果有错误,现在应该已经暴露出来了。

这并不是说 JDK 代码没有错误,只是你应该首先怀疑你的代码。

获取分析器并进行测量。不要猜。

【讨论】:

  • 正如我所说,我在分析器中运行过。所有开销都归因于在 SSL 实现深处创建的 byte[]。
【解决方案4】:

您在什么硬件上运行?你能做一个 netstat 并验证你的连接状态吗?

我已经对 Tomcat 进行了负载测试,并且在 Solaris 上使用 1 GB 堆时,可以轻松实现 500 个新 SSL 请求/秒,运行数小时。此外,您可能需要监控容器中运行的线程数。

【讨论】:

    猜你喜欢
    • 2016-08-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-11-29
    • 2016-09-29
    相关资源
    最近更新 更多