jxmapviewer2 icon indicating copy to clipboard operation
jxmapviewer2 copied to clipboard

Cache Input Stream can leak resources

Open kkieffer opened this issue 4 years ago • 1 comments

When running offline, panning and zooming causes tiles to try and load however connection.getInputStream() throws an UnknownHostException. If the user keeps trying to load new tiles eventually it throws a SocketException - too many open files (even if the network later comes back online, tiles no longer load and throw this exception, see below). I suspect url.openConnection() needs to be closed (closing the input stream does this automatically).

Some info from the web suggests casting the URLConnection to HttpURLConnection, and checking that a call to its getResponseCode() method == HTTP_OK. Also in any case a finally clause to its disconnect() method.

java.net.SocketException: Too many open files
	at java.base/java.net.Socket.createImpl(Socket.java:546)
	at java.base/java.net.Socket.connect(Socket.java:647)
	at java.base/sun.security.ssl.SSLSocketImpl.connect(SSLSocketImpl.java:290)
	at java.base/sun.security.ssl.BaseSSLSocketImpl.connect(BaseSSLSocketImpl.java:173)
	at java.base/sun.net.NetworkClient.doConnect(NetworkClient.java:182)
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:474)
	at java.base/sun.net.www.http.HttpClient.openServer(HttpClient.java:569)
	at java.base/sun.net.www.protocol.https.HttpsClient.<init>(HttpsClient.java:265)
	at java.base/sun.net.www.protocol.https.HttpsClient.New(HttpsClient.java:372)
	at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.getNewHttpClient(AbstractDelegateHttpsURLConnection.java:177)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect0(HttpURLConnection.java:1194)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.plainConnect(HttpURLConnection.java:1082)
	at java.base/sun.net.www.protocol.https.AbstractDelegateHttpsURLConnection.connect(AbstractDelegateHttpsURLConnection.java:163)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream0(HttpURLConnection.java:1595)
	at java.base/sun.net.www.protocol.http.HttpURLConnection.getInputStream(HttpURLConnection.java:1523)
	at java.base/sun.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:224)
	at org.jxmapviewer.viewer.AbstractTileFactory$TileRunner.cacheInputStream(AbstractTileFactory.java:433)

kkieffer avatar Oct 13 '20 01:10 kkieffer

As it turns out, this is not a bug per se, but occurs because the java.net.Socket is opening a native resource (socket handle) and apparently it does not release the native resource until it is garbage collected. In my case I guess the GC was not running often enough to avoid the issue.

My solution is to keep track of a count of tiles that fail to load. When it reaches some threshold I call System.gc(). I know its not advisable to be calling this but it does solve the problem.

Similar issue posted here: https://stackoverflow.com/questions/15917383/java-net-unknownhostexception-and-java-net-socketexception-too-many-open-files/64344960#64344960

kkieffer avatar Oct 14 '20 00:10 kkieffer