Bug 59659 - WsSession leaks (is not GC) if error occurs during the closing process
Summary: WsSession leaks (is not GC) if error occurs during the closing process
Status: RESOLVED FIXED
Alias: None
Product: Tomcat 8
Classification: Unclassified
Component: WebSocket (show other bugs)
Version: 8.5.2
Hardware: PC All
: P2 normal (vote)
Target Milestone: ----
Assignee: Tomcat Developers Mailing List
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2016-06-03 07:32 UTC by Jan Mika
Modified: 2016-06-06 16:30 UTC (History)
0 users



Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Jan Mika 2016-06-03 07:32:48 UTC
Tested on tomee 7.0.0. using tomcat-websocket.jar version 8.5.2.
I found it during the long-term using of WebSockets. After several page switches and re-openings some WsSessions  were not  removed even after the client session finished. It was difficult to reproduce. But here is how to do it more predictably:

Open the HTML page defined below and several time click reload current page. If error occurs on Java side (it means that wsError occurs) the WsSession will not be removed from GC. I tested it mostly with Firefox but it work also on IE 11 etc. JDK 1.7.0_51 64 bit was used.



HTML code:

<!DOCTYPE html>
<html>
<head>
	<meta charset="UTF-8">
	<title>WebSocket Test</title>
	<script>
		var ws = null;
		var i=0;
		var myVar = setInterval(myTimer, 10);
		function myTimer() {
			if(ws) return;
			ws = new WebSocket("ws://localhost:8080/WsMemoryLeak/ws");
			console.log("reconnecting " + i++);
            ws.onopen = function() {
               //ws.send("Message to send");
               console.log("onocpen " + i++);
               ws.close();
               ws = null;
            };
				
            ws.onmessage = function (evt) { 
               var received_msg = evt.data;
               console.log("onmessage " + evt.data);
            };
				
            ws.onclose = function(){
           	 console.log("onclose");
            };

		}
		window.onbeforeunload = function(){
			if(ws) ws.close();
		}
	</script>
</head>
<body>
	<h2>WebSocket test</h2>
</body>

Java Code:

import java.io.IOException;
import java.util.Iterator;
import java.util.concurrent.atomic.AtomicInteger;

import javax.websocket.MessageHandler;
import javax.websocket.OnClose;
import javax.websocket.OnError;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.ServerEndpoint;

import org.apache.tomcat.websocket.WsSession;


@ServerEndpoint(value = "/ws")
public class MyWebsocket {
    private static final AtomicInteger count  = new AtomicInteger (0);
    @OnOpen
    public void wsOpen(Session session){
        WsSession s = (WsSession) session;
        int c = count.incrementAndGet();
        System.out.println("WS Opened " + c);
    }
    
    @OnError
    public void wsError(Session session, Throwable t){
        System.out.println("WS Error ");
        try {
            WsSession s = (WsSession) session;
            s.close();
        } catch (IOException e) {}
    }
    
    @OnClose
    public void wsClosed(Session session){
        int c = count.decrementAndGet();
        System.out.println("WS Closed " + c);
        try {
            session.close();
        } catch (IOException e) {}
    }
}
Comment 1 Mark Thomas 2016-06-06 16:30:00 UTC
Thanks for the report. This was introduced in the connector refactoring so 8.0.x and earlier are not affected.

It has been fixed in 9.0.x for 9.0.0.M7 onwards and 8.5.x for 8.5.3 onwards.