【问题标题】:Jetty WebSocket server won't release binary message byte buffer poolJetty WebSocket 服务器不会释放二进制消息字节缓冲池
【发布时间】:2015-11-20 16:19:14
【问题描述】:

我正在使用 Jetty 的 JSR356 WebSocket 实现编写一个简单的嵌入式 WebSocket 服务器。我的服务器侦听本地端口,Web 应用程序将创建从浏览器到本地服务器的 WebSocket 连接,并将二进制数据发送到服务器。 这是我的服务器代码示例:

服务器:

public class WSServer {

    public static void main(String[] args) {
        Server server = new Server();

        // Connector
        ServerConnector connector = new ServerConnector(server);
        connector.setPort(8080);

        ServletContextHandler ctx = new ServletContextHandler(ServletContextHandler.SESSIONS);
        ctx.setContextPath("/");

        server.setHandler(ctx);
        server.addConnector(connector);

        try {
            // Initialize javax.websocket layer
            ServerContainer wscontainer = WebSocketServerContainerInitializer.configureContext(ctx);

            // Add WebSocket endpoint to javax.websocket layer
            wscontainer.addEndpoint(WSEndpoint.class);
            wscontainer.setDefaultMaxSessionIdleTimeout(0);
            wscontainer.setDefaultMaxTextMessageBufferSize(Integer.MAX_VALUE);
            wscontainer.setDefaultMaxBinaryMessageBufferSize(Integer.MAX_VALUE);

            server.start();
            server.join();
        } catch (Throwable t) {
            t.printStackTrace(System.err);
        }
    }
}

服务器端点:

@ServerEndpoint("/")
public class WSEndpoint {

    @OnOpen
    public void onOpen(Session session) throws IOException {
        session.getBasicRemote().sendText("onOpen");
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        System.out.println("Received text message: " + message);
    }

    @OnMessage
    public void onBinary(ByteBuffer bb, Session session) {
        System.out.println("Got binary message, do nothing to make sure there is no reference to ByteBuffer and Session");
    }

    @OnError
    public void onError(Throwable t) {
        t.printStackTrace();
    }

    @OnClose
    public void onClose(Session session) {

    }
}

在本例中,不对传入的二进制字节缓冲区执行任何操作,以避免出于测试目的对该对象的任何引用。

但是在传输了几个文件的一些测试运行之后,这台服务器的内存使用量显着增加,几乎没有下降。即使我断开连接,内存仍然没有关闭,在我不得不停止服务器之前,它最多需要 1.5 GB 的内存。

然后我转储内存,发现我传输的所有二进制文件都被org.eclipse.jetty.io.MappedByteBufferPool对象保存在内存中,并且从未释放过。 IMO,Jetty 会处理这个 MappedByteBufferPool 并在适当的时候释放内存,因为它没有暴露给我们,但似乎缓冲池从未被释放。

所以我的问题是:

  1. 我的代码做错了吗?
  2. 如果代码没问题,如何解决这个问题?

谢谢!

【问题讨论】:

    标签: java jetty bytebuffer


    【解决方案1】:

    这是 Jetty 9.3.4.v20151007 中修复的错误,并在 9.3.5.v20151012 中进一步完善。

    相关错误:

    • 错误#478829:WebsocketSession 未清理/内存泄漏
    • 错误#474936:WebSocketSessions 并不总是从 openSessions 中清除

    【讨论】:

    • 谢谢,但这两个bug似乎是针对Jetty自己的WebSocket实现的,而不是针对jsr 356实现的,看来我的问题也是一个bug,也许我也应该记录一个bug。
    • JSR356实现是jetty原生websocket实现之上的一层。
    • 最新版本 9.3.5.v20151012 仍然存在同样的问题。
    • 最新发布的其实是9.3.6.v20151106 :-)
    【解决方案2】:

    我想发布我从 Jetty 错误报告中获得的解决方案,感谢 @Joakim Erdfelt 的重播,感谢任何可能遇到相同问题的人:

    对于大文件传输,使用stream而不是ByteBuffer:

    @OnMessage
    public void onBinary(InputStream in, Session session) {
        System.out.println("Got binary message");
    }
    

    但请注意,作为我的测试,此解决方案适用于 IE 和 Chrome,但如果从 Firefox 浏览器传输文件,它仍然会累积 MappedByteBuffer 对象的内存使用量,至少对于当前最新的 Jetty 版本 9.3.6。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-08-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-02-16
      • 1970-01-01
      • 2021-02-25
      • 1970-01-01
      相关资源
      最近更新 更多