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

Memory leak in getTemporaryDirectBuffer when used with the common fork-join pool

XMLWordPrintable

    • b26
    • 24
    • generic
    • generic

      A DESCRIPTION OF THE PROBLEM :
      https://bugs.openjdk.org/browse/JDK-8344882 causes a memory leak when doing I/O using the common fork-join pool, in particular when using anything that calls into Util.getTemporaryDirectBuffer (which includes many basic I/O classes: NioSocketImpl, SocketChannelImpl, IOUtils). The problem is that the common fork-join pool clears thread locals after task completion (https://bugs.openjdk.org/browse/JDK-8285638) and then the thread local BufferCache in sun.nio.ch.Util simply gets garbage collected without freeing the buffers potentially present in the cache (previously manually allocated using Unsafe.allocateMemory). Before JDK-8344882 the buffers allocated by Util.getTemporaryDirectBuffer were registered in a cleaner that correctly ran the cleanup before the buffers in the BufferCache were GCed.

      REGRESSION : Last worked in version 23

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test case code. To debug this I also instrumented the JVM so that each temporary buffer a) gets its own unique id, b) is flagged when it is correctly freed, c) it is registered in a cleaner that prints a warning whenever a buffer is about to get GCed before the underlying memory was freed.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No memory leak
      ACTUAL -
      Memory leak

      ---------- BEGIN SOURCE ----------
      import java.io.*;
      import java.net.*;
      import java.util.stream.*;
      import java.util.concurrent.ThreadLocalRandom;

      public class Test {
      public void run() {
      while (true) {
      IntStream.rangeClosed(0, 24).boxed().parallel().forEach(x -> {
      try {
      Thread.sleep(ThreadLocalRandom.current().nextInt(50));
      URL google = new URL("https://www.google.com/");
      URLConnection conn = google.openConnection();
      BufferedReader in = new BufferedReader(new InputStreamReader(conn.getInputStream()));
      String inputLine;
      while ((inputLine = in.readLine()) != null) {
      }
      in.close();
      } catch (IOException e) {
      System.out.println(e);
      } catch (InterruptedException e) {
      System.out.println(e);
      }
      });
      }
      }

      public void fetchGoogle() {
      }

      public static void main(String[] args) {
      Test test = new Test();
      test.run();
      }
      }
      ---------- END SOURCE ----------

            Unassigned Unassigned
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: