停止Tomcat时Tomcat 8内存泄漏警告

时间:2016-02-11 19:53:45

标签: java tomcat websocket

实现小型微服务架构有以下系统架构:

2个Tomcat8实例在同一台机器上运行,InstanceA在端口8080上运行,InstanceB在端口8081上运行。

它们通过Websocket-connection (javax.websocket.server.ServerEndpoint)连接,

InstanceA是Websocket-Client,InstanceB是WebSocketServer。 实现ServletContextListener接口在tomcat启动时调用contextInitialized(ServletContextEvent arg0)方法。当调用此方法时,我通过

打开WebSocket服务器的Websocket连接

ContainerProvider.getWebSocketContainer().connectToServer(MyClientEndpoint.class, new URI(arService.getProtocol() + "://" + arService.getIp() + ":" + arService.getPort() + arService.getEndPointUrl()));

连接工作完全正常但是当我关闭InstanceA时,我得到以下StackTrace:

WARNING: The web application [AuronGateway] appears to have started a thread named [Thread-5] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(Unknown Source)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 java.lang.Thread.run(Unknown Source)

奇怪的是,我只能在使用Oracle JDK的Microsoft Windows(在Win7和Win10上测试它 - 同样的警告)上收到此警告。 使用OpenJDK在Ubuntu14.04上部署相同的代码时,我没有收到警告。 我使用Eclipse在两个系统上部署WebApplication和Java 8 / Tomcat8。

在调试应用程序时,我注意到websocket-Connection正确关闭。

修改 在websocketServer-Side(InstanceB)上我在onError方法中得到以下异常:

java.io.IOException: Eine vorhandene Verbindung wurde vom Remotehost geschlossen
    at sun.nio.ch.SocketDispatcher.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(Unknown Source)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(Unknown Source)
    at sun.nio.ch.IOUtil.write(Unknown Source)
    at sun.nio.ch.SocketChannelImpl.write(Unknown Source)
    at org.apache.tomcat.util.net.NioChannel.write(NioChannel.java:124)
    at org.apache.tomcat.util.net.NioSelectorPool.write(NioSelectorPool.java:183)
    at org.apache.coyote.http11.upgrade.NioServletOutputStream.doWriteInternal(NioServletOutputStream.java:94)
    at org.apache.coyote.http11.upgrade.NioServletOutputStream.doWrite(NioServletOutputStream.java:61)
    at org.apache.coyote.http11.upgrade.AbstractServletOutputStream.writeInternal(AbstractServletOutputStream.java:165)
    at org.apache.coyote.http11.upgrade.AbstractServletOutputStream.write(AbstractServletOutputStream.java:132)
    at org.apache.tomcat.websocket.server.WsRemoteEndpointImplServer.onWritePossible(WsRemoteEndpointImplServer.java:99)
    at org.apache.tomcat.websocket.server.WsRemoteEndpointImplServer.doWrite(WsRemoteEndpointImplServer.java:80)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.writeMessagePart(WsRemoteEndpointImplBase.java:452)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessage(WsRemoteEndpointImplBase.java:340)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:272)
    at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:586)
    at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:488)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.onError(WsHttpUpgradeHandler.java:150)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.access$300(WsHttpUpgradeHandler.java:48)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onError(WsHttpUpgradeHandler.java:211)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:194)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
    at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:647)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)

EDIT2: 我发现当只连接到websocket-Server时,警告并没有显示出来。它仅在通过

发送一些文本时出现
session.getBasicRemote().sendText("TestMessage");

EDIT3: 设置一个Testproject,它是WebSocketClient的实现:
Startup.java

package de.test.client;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

import javax.servlet.ServletContextEvent;
import javax.servlet.ServletContextListener;
import javax.websocket.ContainerProvider;
import javax.websocket.DeploymentException;
import javax.websocket.Session;

public class Startup implements ServletContextListener
{
    Session session = null;
    @Override
    public void contextDestroyed(ServletContextEvent arg0) {
        System.out.println("stopped Session");
    }

    @Override
    public void contextInitialized(ServletContextEvent arg0) {
        System.out.println("try to establish Connection");
            try {
                this.session = ContainerProvider.getWebSocketContainer().connectToServer(TestClient.class,
                        new URI("ws://127.0.0.1:8081/TestServer/wsEndMessageBroker"));

                session.getBasicRemote().sendText("Hello WebsocketServer");
            } catch (DeploymentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (URISyntaxException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
    }
}

TestClient.java

package de.test.client;

import javax.websocket.ClientEndpoint;
import javax.websocket.CloseReason;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;

@ClientEndpoint
public class TestClient {

        @OnOpen
        public void onOpen(final Session userSession)
        {
            System.out.println("Connection established");
        }

        @OnClose
        public void onClose(final Session userSession, final CloseReason reason)
        {
            System.out.println("close am Clientendpoint(MessageBroker-Service)");
        }

        @OnMessage
        public void onMessage(String jsonMessage)
        {
            System.out.println("message: " + jsonMessage);
        }
        @OnError
        public void onError(Throwable error)
        {
            error.printStackTrace();
        }
}

WebSocketServer:

TestServer.java

package de.test.server;

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("/wsEndMessageBroker")
public class TestServer
{
    public TestServer()
    {
        System.out.println("TestServer started");
    }

    @OnOpen
    public void onOpen(Session session)
    {
        System.out.println("New Connection established SessionID: " + session.getId());
    }

    @OnMessage
    public void message(Session session, String jsonMessage)
    {
        System.out.println("new Message: " + jsonMessage);
    }
    @OnClose
    public void onClose(Session session)
    {
        System.out.println("Closed Connection: " + session.getId());
    }
    @OnError
    public void onError(Throwable error)
    {
        error.printStackTrace();
        System.out.println("Connection were closed unexpected");
    }
}

Log ClientSide

INFORMATION: Initializing ProtocolHandler ["http-nio-8080"]
Feb 12, 2016 9:54:29 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFORMATION: Using a shared selector for servlet write/read
Feb 12, 2016 9:54:29 AM org.apache.coyote.AbstractProtocol init
INFORMATION: Initializing ProtocolHandler ["ajp-nio-8009"]
Feb 12, 2016 9:54:29 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFORMATION: Using a shared selector for servlet write/read
Feb 12, 2016 9:54:29 AM org.apache.catalina.startup.Catalina load
INFORMATION: Initialization processed in 787 ms
Feb 12, 2016 9:54:29 AM org.apache.catalina.core.StandardService startInternal
INFORMATION: Starting service Catalina
Feb 12, 2016 9:54:29 AM org.apache.catalina.core.StandardEngine startInternal
INFORMATION: Starting Servlet Engine: Apache Tomcat/8.0.32
Feb 12, 2016 9:54:30 AM org.apache.jasper.servlet.TldScanner scanJars
INFORMATION: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Feb 12, 2016 9:54:30 AM org.apache.jasper.servlet.TldScanner scanJars
INFORMATION: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Versuche Verbindung aufzubauen
Connection established
Feb 12, 2016 9:54:30 AM org.apache.coyote.AbstractProtocol start
INFORMATION: Starting ProtocolHandler ["http-nio-8080"]
Feb 12, 2016 9:54:30 AM org.apache.coyote.AbstractProtocol start
INFORMATION: Starting ProtocolHandler ["ajp-nio-8009"]
Feb 12, 2016 9:54:30 AM org.apache.catalina.startup.Catalina start
INFORMATION: Server startup in 956 ms
Feb 12, 2016 9:54:34 AM org.apache.catalina.core.StandardServer await
INFORMATION: A valid shutdown command was received via the shutdown port. Stopping the Server instance.
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol pause
INFORMATION: Pausing ProtocolHandler ["http-nio-8080"]
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol pause
INFORMATION: Pausing ProtocolHandler ["ajp-nio-8009"]
Feb 12, 2016 9:54:34 AM org.apache.catalina.core.StandardService stopInternal
INFORMATION: Stopping service Catalina
stopped Session
Feb 12, 2016 9:54:34 AM org.apache.catalina.loader.WebappClassLoaderBase clearReferencesThreads
WARNUNG: The web application [TestClient] appears to have started a thread named [Thread-5] but has failed to stop it. This is very likely to create a memory leak. Stack trace of thread:
 sun.misc.Unsafe.park(Native Method)
 java.util.concurrent.locks.LockSupport.park(Unknown Source)
 java.util.concurrent.locks.AbstractQueuedSynchronizer$ConditionObject.await(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ScheduledThreadPoolExecutor$DelayedWorkQueue.take(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.getTask(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
 java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
 java.lang.Thread.run(Unknown Source)
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol stop
INFORMATION: Stopping ProtocolHandler ["http-nio-8080"]
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol stop
INFORMATION: Stopping ProtocolHandler ["ajp-nio-8009"]
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol destroy
INFORMATION: Destroying ProtocolHandler ["http-nio-8080"]
Feb 12, 2016 9:54:34 AM org.apache.coyote.AbstractProtocol destroy
INFORMATION: Destroying ProtocolHandler ["ajp-nio-8009"]

Log ServerSide

Feb 12, 2016 9:54:26 AM org.apache.coyote.AbstractProtocol init
INFORMATION: Initializing ProtocolHandler ["http-nio-8081"]
Feb 12, 2016 9:54:26 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFORMATION: Using a shared selector for servlet write/read
Feb 12, 2016 9:54:26 AM org.apache.coyote.AbstractProtocol init
INFORMATION: Initializing ProtocolHandler ["ajp-nio-8010"]
Feb 12, 2016 9:54:26 AM org.apache.tomcat.util.net.NioSelectorPool getSharedSelector
INFORMATION: Using a shared selector for servlet write/read
Feb 12, 2016 9:54:26 AM org.apache.catalina.startup.Catalina load
INFORMATION: Initialization processed in 992 ms
Feb 12, 2016 9:54:26 AM org.apache.catalina.core.StandardService startInternal
INFORMATION: Starting service Catalina
Feb 12, 2016 9:54:26 AM org.apache.catalina.core.StandardEngine startInternal
INFORMATION: Starting Servlet Engine: Apache Tomcat/8.0.32
Feb 12, 2016 9:54:27 AM org.apache.jasper.servlet.TldScanner scanJars
INFORMATION: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Feb 12, 2016 9:54:27 AM org.apache.jasper.servlet.TldScanner scanJars
INFORMATION: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Feb 12, 2016 9:54:27 AM org.apache.coyote.AbstractProtocol start
INFORMATION: Starting ProtocolHandler ["http-nio-8081"]
Feb 12, 2016 9:54:27 AM org.apache.coyote.AbstractProtocol start
INFORMATION: Starting ProtocolHandler ["ajp-nio-8010"]
Feb 12, 2016 9:54:27 AM org.apache.catalina.startup.Catalina start
INFORMATION: Server startup in 895 ms
TestServer started
New Connection established SessionID: 0
new Message: Hello WebsocketServer
java.io.IOException: Unable to write the complete message as the WebSocket connection has been closed
    at org.apache.tomcat.websocket.WsSession.registerFuture(WsSession.java:664)
    at org.apache.tomcat.websocket.FutureToSendHandler.get(FutureToSendHandler.java:92)
    at org.apache.tomcat.websocket.WsRemoteEndpointImplBase.startMessageBlock(WsRemoteEndpointImplBase.java:277)
    at org.apache.tomcat.websocket.WsSession.sendCloseMessage(WsSession.java:586)
    at org.apache.tomcat.websocket.WsSession.doClose(WsSession.java:488)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.onError(WsHttpUpgradeHandler.java:150)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler.access$300(WsHttpUpgradeHandler.java:48)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onError(WsHttpUpgradeHandler.java:211)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:194)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
    at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:647)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Connection were closed unexpected
Closed Connection: 0
java.io.IOException: Eine vorhandene Verbindung wurde vom Remotehost geschlossen
    at sun.nio.ch.SocketDispatcher.read0(Native Method)
    at sun.nio.ch.SocketDispatcher.read(Unknown Source)
    at sun.nio.ch.IOUtil.readIntoNativeBuffer(Unknown Source)
    at sun.nio.ch.IOUtil.read(Unknown Source)
    at sun.nio.ch.SocketChannelImpl.read(Unknown Source)
    at org.apache.tomcat.util.net.NioChannel.read(NioChannel.java:137)
    at org.apache.coyote.http11.upgrade.NioServletInputStream.fillReadBuffer(NioServletInputStream.java:136)
    at org.apache.coyote.http11.upgrade.NioServletInputStream.doRead(NioServletInputStream.java:80)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.read(AbstractServletInputStream.java:124)
    at org.apache.tomcat.websocket.server.WsFrameServer.onDataAvailable(WsFrameServer.java:60)
    at org.apache.tomcat.websocket.server.WsHttpUpgradeHandler$WsReadListener.onDataAvailable(WsHttpUpgradeHandler.java:186)
    at org.apache.coyote.http11.upgrade.AbstractServletInputStream.onDataAvailable(AbstractServletInputStream.java:198)
    at org.apache.coyote.http11.upgrade.AbstractProcessor.upgradeDispatch(AbstractProcessor.java:96)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:647)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1500)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1456)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.lang.Thread.run(Unknown Source)
Connection were closed unexpected

1 个答案:

答案 0 :(得分:2)

堆栈跟踪表明创建了一个名为" Thread-5"的线程。应用程序关闭时尚未停止。这可能只是被视为警告,因为tomcat能够handle such problems。但是,每次重新部署应用程序后,如果不重新启动tomcat,它也可能是导致内存泄漏的原因。

你可以在java.lang.Thread类中设置一个条件断点,以便找出具有名称" Thread-5"的线程的位置。创建了。 在找到线程的创建者之后,您可以研究如何正常关闭创建此线程的组件。

关闭功能可以放在ServletContextListener的contextDestroyed()方法中,也可以放在Spring @PreDestroy注释的方法中。