【问题标题】:Tomcat gradually running out of memory with WebSocket apps deployedTomcat 在部署 WebSocket 应用程序后逐渐耗尽内存
【发布时间】:2017-12-27 18:47:09
【问题描述】:

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

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

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

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

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

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

Dominator Tree 目前有 106,000 个条目,其中大部分是 WsFrameServer 类。

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

提前致谢。

编辑:我不确定这是否有帮助,但这是 VisualVM 监视器的样子:

【问题讨论】:

    标签: java tomcat memory websocket eclipse-mat


    【解决方案1】:

    没有更多细节很难确定,但这可能与您的会话保留有关。 我认为正在发生的是 WsFrameServer 扩展 WsFrameBase is added into the session.
    如果您有无限的会话保留策略,那么您最终会耗尽内存。

    尝试设置一个非0的sessionTimeout

    【讨论】:

    • 我的 conf\web.xml 指定以下内容: 30 这不会在任何 webapp 中被覆盖/WEB-INF/web.xml 要么。我需要在别处指定吗?
    • 使用堆转储尝试查看哪个类持有对持有所有WsFrameServers 的ConcurrentHashMap 的引用,它应该对这个问题有更多的了解。您还在使用持久会话管理器吗?
    • 我目前没有使用持久会话管理器。现在检查 Eclipse MAT 以获取对 ConcurrentHashMap 的引用。
    • @Tommo 那么实际的解决方案是什么?您更新了哪些属性?
    【解决方案2】:

    您的问题中缺少代码。 (尤其是你如何管理 websocket 连接)

    您是否在异步模式下使用了带有某个连接列表的tomcat?

    您不会忘记将关闭 AND 错误事件绑定到从列表中删除错误连接的代码?

    【讨论】:

    • 我不完全确定你在问什么。据我所知,我没有在异步模式下使用 tomcat。我正在维护一个包含对会话的引用的数据结构,这些会话在关闭事件期间从数据结构中删除。目前,我不会在错误事件期间删​​除会话。
    • 这将很难解释。使用 SSE(离 websocket 不远)例如golb.hplar.ch/p/Server-Sent-Events-with-Spring 你有emitter.onCompletion(() -> this.emitters.remove(emitter));发射器.onTimeout(() -> this.emitters.remove(发射器));这是管理 websocket / SSE 发射器的方法。如果你使用 session 来存储 websocket,你为什么使用 websocket 呢? session 意味着你已经在一个用户上下文中,所以发回数据,不需要 websocket。
    【解决方案3】:

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

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

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

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

    【讨论】:

      猜你喜欢
      • 2017-04-08
      • 2014-09-05
      • 1970-01-01
      • 2018-01-14
      • 1970-01-01
      • 1970-01-01
      • 2017-06-02
      • 2012-11-22
      相关资源
      最近更新 更多