2015-11-11 25 views
1

我正在使用Jetty的JSR356 WebSocket实现编写一个简单的嵌入式WebSocket服务器。我的服务器监听本地端口,Web应用程序将创建从浏览器到本地服务器的WebSocket连接,并将二进制数据发送到服务器。 这里是我的服务器的代码示例:Jetty 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. 如果代码没问题,该如何解决这个问题?

谢谢!

回答

0

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

相关的bug:

  • 错误#478829:WebsocketSession没有清理/内存泄露
  • 错误#474936:WebSocketSessions并不总是从openSessions
+0

谢谢,但这两个错误似乎是针对Jetty自己的WebSocket实现,而不是jsr 356实现,看起来像我的问题也是一个错误,也许我应该记录一个错误。 –

+0

JSR356实现是在jetty本地websocket实现之上的一个层。 –

+0

尽管最新版本9.3.5.v20151012仍然存在相同的问题。 –

1

清理出来,我想发布我从Jetty bug报告中获得的解决方案,感谢来自@Joakim Erdfelt的重播,对于任何可能有相同问题的人:

对于大文件传输,使用流而不是字节缓冲区:

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

但是,请注意,我的测试中,该解决方案工作正常IE和Chrome,但如果从Firefox浏览器传输文件,它仍然累计内存使用情况由MappedByteBuffer对象创建,用于当前最新的Jetty版本9.3.6。