Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8228568

resource leak caused by the setting or getting a socket option on SocketChannel

XMLWordPrintable

    • x86_64
    • linux

      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


            chegar Chris Hegarty
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: