Tomcat 随着部署的 WebSocket 应用程序逐渐 运行 内存不足
Tomcat gradually running out of memory with WebSocket apps deployed
我在 AWS 机器上安装了 Tomcat 8.5.9 运行,其中部署了 10 个不同的 WebSocket 应用程序,每个应用程序基本上都充当消息代理。 https 连接器使用 Http11NioProtocol。我设置的唯一参数是 maxThreads=200 以及证书信息。
请求量不是很高。自周一早上以来已经 运行,这里是经理状态:
Max threads: 200
Current thread count: 38
Current thread busy: 0
Keep alive sockets count: 1
Max processing time: 234 ms
Processing time: 17.254 s
Request count: 33351
Error count: 325
Bytes received: 0.00 MB
Bytes sent: 34.07 MB
几天后,我注意到内存使用量继续增长。我必须大约每两周左右重新启动一次 Tomcat 服务,以防止出现 OutOfMemoryException。
我一直在使用 Eclipse MAT 进行堆转储和分析,它始终指向 WsFrameServer class 作为问题嫌疑人。最近的转储显示如下:
5,146 instances of "org.apache.tomcat.websocket.server.WsFrameServer",
loaded by "java.net.URLClassLoader @ 0x6c0047c28" occupy 1,383,143,200
(73.13%) bytes. These instances are referenced from one instance of
"java.util.concurrent.ConcurrentHashMap$Node[]"
Dominator Tree 目前有 106,000 个条目,其中大部分是 WsFrameServer class。
是我做错了什么还是"normal"? Tomcat 或连接器上是否有我应该设置的任何特定设置以防止这种情况发生?
提前致谢。
编辑:我不确定这是否有帮助,但这是 VisualVM 监视器的样子:
如果没有更多详细信息,很难确定,但这可能与您的会话保留有关。
我认为正在发生的事情是扩展 WsFrameBase
is added into the session.
的 WsFrameServer
如果您有无限的会话保留策略,那么您最终会 运行 内存不足。
尝试设置一个非 0 sessionTimeout
您的问题缺少代码。 (特别是你如何管理 websocket 连接)
您是否在异步模式下使用了 tomcat 和某处的连接列表?
您不会忘记将关闭和错误事件绑定到从列表中删除错误连接的代码吗?
众所周知,Java GC 是惰性的。它的内存会不断增长,直到不能再有内存时,就会触发GC来收集垃圾。
从你的VisualVM的截图中,我们可以看到内存使用是比较正常的:随着时间的推移,内存使用越来越多,GC后内存使用下降。
所以我想知道你的应用程序是否真的会因为OOM而崩溃。您可以在您的测试环境中尝试,并获取 OOM JVM 转储进行分析,这更有用。
顺便说一下,我建议 VisualVM 而不是 MAT,因为 MAT 将包含一些 unreachable 对象作为 GC 根。它会使内存分析效率非常低,并给出与我在我们的一个项目中遇到的其他工具不同的结果。
我在 AWS 机器上安装了 Tomcat 8.5.9 运行,其中部署了 10 个不同的 WebSocket 应用程序,每个应用程序基本上都充当消息代理。 https 连接器使用 Http11NioProtocol。我设置的唯一参数是 maxThreads=200 以及证书信息。
请求量不是很高。自周一早上以来已经 运行,这里是经理状态:
Max threads: 200
Current thread count: 38
Current thread busy: 0
Keep alive sockets count: 1
Max processing time: 234 ms
Processing time: 17.254 s
Request count: 33351
Error count: 325
Bytes received: 0.00 MB
Bytes sent: 34.07 MB
几天后,我注意到内存使用量继续增长。我必须大约每两周左右重新启动一次 Tomcat 服务,以防止出现 OutOfMemoryException。
我一直在使用 Eclipse MAT 进行堆转储和分析,它始终指向 WsFrameServer class 作为问题嫌疑人。最近的转储显示如下:
5,146 instances of "org.apache.tomcat.websocket.server.WsFrameServer",
loaded by "java.net.URLClassLoader @ 0x6c0047c28" occupy 1,383,143,200
(73.13%) bytes. These instances are referenced from one instance of
"java.util.concurrent.ConcurrentHashMap$Node[]"
Dominator Tree 目前有 106,000 个条目,其中大部分是 WsFrameServer class。
是我做错了什么还是"normal"? Tomcat 或连接器上是否有我应该设置的任何特定设置以防止这种情况发生?
提前致谢。
编辑:我不确定这是否有帮助,但这是 VisualVM 监视器的样子:
如果没有更多详细信息,很难确定,但这可能与您的会话保留有关。
我认为正在发生的事情是扩展 WsFrameBase
is added into the session.
的 WsFrameServer
如果您有无限的会话保留策略,那么您最终会 运行 内存不足。
尝试设置一个非 0 sessionTimeout
您的问题缺少代码。 (特别是你如何管理 websocket 连接)
您是否在异步模式下使用了 tomcat 和某处的连接列表?
您不会忘记将关闭和错误事件绑定到从列表中删除错误连接的代码吗?
众所周知,Java GC 是惰性的。它的内存会不断增长,直到不能再有内存时,就会触发GC来收集垃圾。
从你的VisualVM的截图中,我们可以看到内存使用是比较正常的:随着时间的推移,内存使用越来越多,GC后内存使用下降。
所以我想知道你的应用程序是否真的会因为OOM而崩溃。您可以在您的测试环境中尝试,并获取 OOM JVM 转储进行分析,这更有用。
顺便说一下,我建议 VisualVM 而不是 MAT,因为 MAT 将包含一些 unreachable 对象作为 GC 根。它会使内存分析效率非常低,并给出与我在我们的一个项目中遇到的其他工具不同的结果。