Java 随着WebSocket应用程序的部署,Tomcat逐渐耗尽内存

Java 随着WebSocket应用程序的部署,Tomcat逐渐耗尽内存,java,tomcat,memory,websocket,eclipse-mat,Java,Tomcat,Memory,Websocket,Eclipse Mat,我让Tomcat 8.5.9在AWS机器上运行,并部署了10个不同的WebSocket应用程序,每个应用程序基本上充当消息代理。https连接器正在使用HTTP11NIO协议。我唯一设置的参数是maxThreads=200以及证书信息 请求量不是很高。它从周一早上开始运行,下面是经理状态说明: 最大线程数:200 当前线程数:38 当前线程正忙:0 保持活动套接字计数:1 最大处理时间:234毫秒 处理时间:17.254秒 请求计数:33351 错误计数:325 接收的字节数:0.00 MB 发

我让Tomcat 8.5.9在AWS机器上运行,并部署了10个不同的WebSocket应用程序,每个应用程序基本上充当消息代理。https连接器正在使用HTTP11NIO协议。我唯一设置的参数是maxThreads=200以及证书信息

请求量不是很高。它从周一早上开始运行,下面是经理状态说明:

最大线程数:200
当前线程数:38
当前线程正忙:0
保持活动套接字计数:1
最大处理时间:234毫秒
处理时间:17.254秒
请求计数:33351
错误计数:325
接收的字节数:0.00 MB
发送字节:34.07 MB

几天后,我注意到内存使用量继续增长。我必须大约每两周重新启动一次Tomcat服务,以防止出现OutOfMemoryException

我一直在使用EclipseMat进行堆转储和分析,它总是指出WsFrameServer类是可疑的问题。最近的转储显示以下内容:

5146个“org.apache.tomcat.websocket.server.WsFrameServer”实例,
由“java.net.URLClassLoader@0x6c0047c28”加载,占用1383143200
(73.13%)字节。这些实例引用自的一个实例
“java.util.concurrent.ConcurrentHashMap$Node[]”

支配树目前有106000个条目,其中大部分是WsFrameServer类

我做错了什么,还是这“正常”?Tomcat或连接器上是否有任何特定的设置,我应该设置这些设置来防止这种情况发生

提前谢谢

编辑:我不确定这是否有用,但以下是VisualVM监视器的外观:


如果没有更多细节,很难确定,但这可能与会话保留有关。 我认为正在发生的是
WsFrameServer
,它扩展了
WsFrameBase

如果您有一个无限会话保留策略,那么您最终将耗尽内存


尝试设置一个非0的
sessionTimeout

问题中缺少代码。(特别是如何管理websocket连接)

您是否在异步模式下使用tomcat并在某处列出连接列表


您不会忘记将close和error事件绑定到代码,以从列表中删除错误连接?

众所周知,Java GC是懒惰的。它的内存将继续增长,直到它不能拥有更多的内存,然后会触发GC来收集垃圾

从VisualVM的屏幕截图中,我们可以看到内存使用是相对正常的:随着时间的推移,使用的内存越来越多,GC后内存使用率下降

所以我想知道你的应用程序是否真的会因为OOM而崩溃。您可以在您的测试环境中尝试它,并获得OOM JVM转储进行分析,这更有用


顺便说一下,我建议VisualVM优先于MAT,因为MAT将包括一些对象作为GC根。它将使内存分析效率非常低,并给出与我在一个项目中遇到的其他工具不同的结果。

My conf\web.xml指定了以下内容:30这也不会在任何webapp/web-INF/web.xml中被覆盖。我需要在其他地方指定吗?使用堆转储,尝试查看哪个类包含对
ConcurrentHashMap
的引用,该类包含所有
WsFrameServer
的引用,它应该能更清楚地说明这个问题。您是否正在使用持久会话管理器?我当前没有使用持久会话管理器。现在检查EclipseMat,查看持有对
ConcurrentHashMap
的引用的类。我不完全确定您在问什么。据我所知,我没有在异步模式下使用tomcat。我维护的数据结构包含对会话的引用,这些会话在关闭事件期间从数据结构中删除。我目前没有在错误事件期间删除会话。这将很难解释。例如,对于SSE(离websocket不远),您有emitter.onCompletion(()->this.emitters.remove(emitter));emitter.onTimeout(()->this.emitters.remove(emitter));这是管理websocket/SSE发射器的方法。如果您使用会话来存储websocket,为什么要使用websocket来存储?会话意味着您已经处于用户上下文中,所以发送回数据,不需要websocket。