2015-11-11 27 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。