Skip to main content

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [List Home]
[jetty-users] Encounter memory leak/accumulation issue


Hi jetty-users,

I would like to see is there a way to resolve this issue: either through coding or configuration changes.  Any advice and suggestions will be greatly appreciated.
 
I have encountered the memory leak/accumulation issue using a _javascript_ WebSocket client communicates with a local application Jetty WebSocket server (using Jetty's WebSocket JSR356 implementation).  I have tried both Jetty 9.3.3.v20150827 and 9.3.5.v20151012 and the memory leak issue can both be observed.  Java version is "1.8.0_60".

What I want to achieve is sending files (one at a time as instructed by the user) from the Browser _javascript_ WebSocket client to the Jetty WebSocket server for processing.

Two memory leak/accumulation issues are observed (using Eclipse Memory Analyzer) at the Jetty WebSocket server side:
  • Each unique files sent got cached in an org.eclipse.jetty.io.MappedByteBufferPool object.  The cache persists even with the client terminated or server timeout the connection/session.  If the client keep send different files, eventually the OutOfMemoryError can occurred at the Jetty WebSocket server because the MappedByteBufferPool object memory usage just keep growing.
    • Is there a way to limit the max number of cached entries or totally disable the cache in this MappedByteBufferPool object?
    • I also tried adding the -XX:MaxDirectMemorySize=200m jvm option but it the MappedByteBufferPool object memory usage is still growing.
  • Each new connection/JsrSession is referenced in the org.eclipse.jetty.websocket.server.WebSocketServerFactory object even after the session is closed.  The last onBinary (OnMessage) ByteBuffer argument is cached with the JsrSession.  After several open/close sessions, the memory usage of the WebSocketServerFactory object just keep growing.  BTW, the WebSocketServerFactory object also have a reference to the MappedByteBufferPool object mentioned above.
    • Is there a way to make the WebSocketServerFactory object not to cache the all the previous closed JsrSession objects? 


Below are excerpted (with simplification) from both client and server sides:


================================================================================ 

_javascript_ WebSocket client side:
=============================================
function sendFile(file) {
    var reader = new FileReader();
    reader.readAsArrayBuffer(file);
    reader._onload_ = function() {
        // this websocket object has been setup somewhere else in advance with binaryType = "blob"
        websocket.send(reader.result);
    }
}
 
Jetty WebSocket server side:
======================================
WSServer.java
-------------

package mytestapp;

import javax.websocket.server.ServerContainer;
import org.eclipse.jetty.server.Server;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.servlet.ServletContextHandler;
import org.eclipse.jetty.websocket.jsr356.server.deploy.WebSocketServerContainerInitializer;

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);
        }
    }
}


WSEndpoint.java
---------------

package mytestapp;

import java.io.IOException;
import java.nio.ByteBuffer;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

@ServerEndpoint("/")
public class WSEndpoint {

    @OnOpen
    public void onOpen(Session session) throws IOException {
        System.out.println("onOpen");
    }

    @OnMessage
    public void onText(String message, Session session) {
        System.out.println("onText");
    }

    @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) {
        System.out.println("Received error: " + t.getMessage());
    }

    @OnClose
    public void onClose(Session session) {
        System.out.println("onClose");
    }
}

================================================================================ 


Thanks,
Mike


Back to the top