// // ======================================================================== // Copyright (c) 1995-2017 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 // and Apache License v2.0 which accompanies this distribution. // // The Eclipse Public License is available at // http://www.eclipse.org/legal/epl-v10.html // // The Apache License v2.0 is available at // http://www.opensource.org/licenses/apache2.0.php // // You may elect to redistribute this code under either of these licenses. // ======================================================================== // package org.eclipse.jetty.websocket.jsr356.server; import static org.hamcrest.Matchers.lessThan; import java.lang.management.ManagementFactory; import java.lang.management.MemoryMXBean; import java.lang.management.MemoryUsage; import java.net.URI; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; import javax.websocket.ContainerProvider; import javax.websocket.Endpoint; import javax.websocket.EndpointConfig; import javax.websocket.MessageHandler; import javax.websocket.Session; import javax.websocket.WebSocketContainer; import javax.websocket.server.ServerEndpointConfig; 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; import org.eclipse.jetty.websocket.jsr356.server.samples.echo.BasicEchoEndpoint; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; public class MemoryUsageTest { private Server server; private ServerConnector connector; private WebSocketContainer client; @Before public void prepare() throws Exception { server = new Server(); connector = new ServerConnector(server); server.addConnector(connector); ServletContextHandler context = new ServletContextHandler(server, "/", true, false); ServerContainer container = WebSocketServerContainerInitializer.configureContext(context); ServerEndpointConfig config = ServerEndpointConfig.Builder.create(BasicEchoEndpoint.class, "/").build(); container.addEndpoint(config); server.start(); client = ContainerProvider.getWebSocketContainer(); } @After public void dispose() throws Exception { server.stop(); } @SuppressWarnings("unused") @Test public void testMemoryUsage() throws Exception { int sessionCount = 1000; Session[] sessions = new Session[sessionCount]; MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean(); System.gc(); MemoryUsage heapBefore = memoryMXBean.getHeapMemoryUsage(); MemoryUsage nonHeapBefore = memoryMXBean.getNonHeapMemoryUsage(); URI uri = URI.create("ws://localhost:" + connector.getLocalPort()); final CountDownLatch latch = new CountDownLatch(sessionCount); for (int i = 0; i < sessionCount; ++i) { sessions[i] = client.connectToServer(new EndpointAdapter() { @Override public void onMessage(String message) { latch.countDown(); } }, uri); } for (int i = 0; i < sessionCount; ++i) { sessions[i].getBasicRemote().sendText("OK"); } latch.await(5 * sessionCount, TimeUnit.MILLISECONDS); System.gc(); MemoryUsage heapAfter = memoryMXBean.getHeapMemoryUsage(); MemoryUsage nonHeapAfter = memoryMXBean.getNonHeapMemoryUsage(); long heapUsed = heapAfter.getUsed() - heapBefore.getUsed(); long nonHeapUsed = nonHeapAfter.getUsed() - nonHeapBefore.getUsed(); System.out.println("heapUsed = " + heapUsed); System.out.println("nonHeapUsed = " + nonHeapUsed); // new CountDownLatch(1).await(); // Assume no more than 25 KiB per session pair (client and server). long expected = 25 * 1024 * sessionCount; Assert.assertThat("heap used", heapUsed,lessThan(expected)); } private static abstract class EndpointAdapter extends Endpoint implements MessageHandler.Whole<String> { @Override public void onOpen(Session session, EndpointConfig config) { session.addMessageHandler(this); } } }