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

ConcurrentLinkedQueue memory leak

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 8u60
    • core-libs

      FULL PRODUCT VERSION :
      java version "1.8.0_60"
      Java(TM) SE Runtime Environment (build 1.8.0_60-b27)
      Java HotSpot(TM) 64-Bit Server VM (build 25.60-b23, mixed mode)


      A DESCRIPTION OF THE PROBLEM :
      ConcurrentLinkedQueue leaks memory when removing the last element of a non-empty queue.

      This has been reported for the Cassandra project (see https://issues.apache.org/jira/browse/CASSANDRA-9549, the last comment on 15-Jul-2015), and in the Jetty project (see https://bugs.eclipse.org/bugs/show_bug.cgi?id=477817)

      The problem is in method remove(Object), when the object last in the queue is the one to remove.
      What happens is that casItem() will succeed, but next = succ(p) will be null (since p is the last node), so the next "if" statement will not be entered and the last Node not unlinked.



      ADDITIONAL REGRESSION INFORMATION:
      AFAIK, this bug is present in the latest JDK 7, 8 and 9 releases.

      STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
      Run the test case below.

      EXPECTED VERSUS ACTUAL BEHAVIOR :
      EXPECTED -
      No memory leaks.
      ACTUAL -
      Memory is leaked and when running with very small heaps (say 1 MiB), it takes about 50k iterations to exhaust the heap.

      Note also that because the last Node instance is never removed, more Nodes are appended and each further add/remove operation will have to navigate the linked list until the end with much CPU consumption and slowdown of performance of the methods.

      REPRODUCIBILITY :
      This bug can be reproduced always.

      ---------- BEGIN SOURCE ----------
      public class CLQBug
      {
          public static void main(String[] args)
          {
              Queue<Object> queue = new ConcurrentLinkedQueue<>();
              queue.offer(new Object());

              Object item = new Object();

              long iterations = 0;
              try
              {
                  while (true)
                  {
                      ++iterations;
                      queue.offer(item);
                      queue.remove(item);
                  }
              }
              catch (OutOfMemoryError e)
              {
                  queue = null;
                  System.err.println("iterations: " + iterations);
                  throw e;
              }
          }
      }

      ---------- END SOURCE ----------

      CUSTOMER SUBMITTED WORKAROUND :
      No workaround, if not making sure that the object you are removing is not the last.

            martin Martin Buchholz
            webbuggrp Webbug Group
            Votes:
            0 Vote for this issue
            Watchers:
            3 Start watching this issue

              Created:
              Updated:
              Resolved: