A DESCRIPTION OF THE PROBLEM :
If one sets jdk.net.ExtendedSocketOptions on a socket channel there seems to be a resource leak for socket file handles. This is reproduceable and can be obtained by the lsof tool in Linux Systems.
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
import jdk.net.ExtendedSocketOptions;
/**
* Test-code to reproduce resource leak caused by the usage of ExendedSocketOptions
*
* Linux Distribution:
* NAME="openSUSE Leap"
* VERSION="15.1 "
* ID="opensuse-leap"
* ID_LIKE="suse opensuse"
* VERSION_ID="15.1"
* PRETTY_NAME="openSUSE Leap 15.1"
* ANSI_COLOR="0;32"
* CPE_NAME="cpe:/o:opensuse:leap:15.1"
* BUG_REPORT_URL="https://bugs.opensuse.org"
* HOME_URL="https://www.opensuse.org/"
*
* Java-Version:
* openjdk 12.0.2 2019-07-16
* OpenJDK Runtime Environment (build 12.0.2+10)
* OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)
*
* Compile with:
* javac SocketTest.java
* Run with:
* java SocketTest [port number]
*
* to detect resource leak, use unix command lsof -P -p [pid of process]
* this command yields a large number of entries of the form
* java pid user 104u sock 0,9 0t0 5791955 protocol: TCPv6
*
*/
public class SocketTest {
private static final int TESTNUM = 100;
public static void main(String[] args) {
if (args.length < 2) {
printUsage();
} else {
try {
final int port = Integer.parseInt(args[0]);
final int num = Integer.parseInt(args[1]);
final boolean useExtendedSocketOptions = num > 0;
new SocketTest().doTest(port, useExtendedSocketOptions);
} catch (NumberFormatException e) {
printUsage();
}
}
}
public static void printUsage() {
System.out.println("usage: java SocketTest [port] [0 (=without extended socket options)/1 (=with extended socket options)]");
}
private void doTest(final int port, boolean useExtendedSocketOptions) {
try(ServerSocketChannel ssc = ServerSocketChannel.open()) {
ssc.configureBlocking(true);
ssc.socket().bind(new InetSocketAddress(port));
final Thread acceptorThread = new Thread("acceptor") {
int ctr = 0;
@Override
public void run() {
while(ctr < TESTNUM) {
try(SocketChannel sc = ssc.accept()) {
System.out.println("accepted counter=" + ++ctr);
// resource leak is caused by the next line
if (useExtendedSocketOptions) {
sc.socket().setOption(ExtendedSocketOptions.TCP_KEEPIDLE, Integer.valueOf(30));
}
} catch (UnsupportedOperationException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
final Thread clientThread = new Thread("client") {
@Override
public void run() {
for (int i = 1; i <= TESTNUM; i++) {
try (Socket s = new Socket("localhost", port)) {
System.out.println("open counter=" + i);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
acceptorThread.start();
clientThread.start();
clientThread.join();
System.out.println("clientThread joined");
acceptorThread.join();
System.out.println("acceptorThread joined");
try (Scanner keyIn = new Scanner(System.in)) {
System.out.print("please execute lsof -P -p [pid of this process], then press enter key to continue");
keyIn.nextLine();
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
If one sets jdk.net.ExtendedSocketOptions on a socket channel there seems to be a resource leak for socket file handles. This is reproduceable and can be obtained by the lsof tool in Linux Systems.
---------- BEGIN SOURCE ----------
import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.Scanner;
import jdk.net.ExtendedSocketOptions;
/**
* Test-code to reproduce resource leak caused by the usage of ExendedSocketOptions
*
* Linux Distribution:
* NAME="openSUSE Leap"
* VERSION="15.1 "
* ID="opensuse-leap"
* ID_LIKE="suse opensuse"
* VERSION_ID="15.1"
* PRETTY_NAME="openSUSE Leap 15.1"
* ANSI_COLOR="0;32"
* CPE_NAME="cpe:/o:opensuse:leap:15.1"
* BUG_REPORT_URL="https://bugs.opensuse.org"
* HOME_URL="https://www.opensuse.org/"
*
* Java-Version:
* openjdk 12.0.2 2019-07-16
* OpenJDK Runtime Environment (build 12.0.2+10)
* OpenJDK 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)
*
* Compile with:
* javac SocketTest.java
* Run with:
* java SocketTest [port number]
*
* to detect resource leak, use unix command lsof -P -p [pid of process]
* this command yields a large number of entries of the form
* java pid user 104u sock 0,9 0t0 5791955 protocol: TCPv6
*
*/
public class SocketTest {
private static final int TESTNUM = 100;
public static void main(String[] args) {
if (args.length < 2) {
printUsage();
} else {
try {
final int port = Integer.parseInt(args[0]);
final int num = Integer.parseInt(args[1]);
final boolean useExtendedSocketOptions = num > 0;
new SocketTest().doTest(port, useExtendedSocketOptions);
} catch (NumberFormatException e) {
printUsage();
}
}
}
public static void printUsage() {
System.out.println("usage: java SocketTest [port] [0 (=without extended socket options)/1 (=with extended socket options)]");
}
private void doTest(final int port, boolean useExtendedSocketOptions) {
try(ServerSocketChannel ssc = ServerSocketChannel.open()) {
ssc.configureBlocking(true);
ssc.socket().bind(new InetSocketAddress(port));
final Thread acceptorThread = new Thread("acceptor") {
int ctr = 0;
@Override
public void run() {
while(ctr < TESTNUM) {
try(SocketChannel sc = ssc.accept()) {
System.out.println("accepted counter=" + ++ctr);
// resource leak is caused by the next line
if (useExtendedSocketOptions) {
sc.socket().setOption(ExtendedSocketOptions.TCP_KEEPIDLE, Integer.valueOf(30));
}
} catch (UnsupportedOperationException e) {
System.out.println(e.getMessage());
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
final Thread clientThread = new Thread("client") {
@Override
public void run() {
for (int i = 1; i <= TESTNUM; i++) {
try (Socket s = new Socket("localhost", port)) {
System.out.println("open counter=" + i);
} catch (IOException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
};
acceptorThread.start();
clientThread.start();
clientThread.join();
System.out.println("clientThread joined");
acceptorThread.join();
System.out.println("acceptorThread joined");
try (Scanner keyIn = new Scanner(System.in)) {
System.out.print("please execute lsof -P -p [pid of this process], then press enter key to continue");
keyIn.nextLine();
}
} catch (IOException | InterruptedException e) {
throw new RuntimeException(e.getMessage(), e);
}
}
}
---------- END SOURCE ----------
FREQUENCY : always
- duplicates
-
JDK-8222774 (ch) Replace uses of stateLock and blockingLock with j.u.c. locks
- Resolved