diff --git a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java index 62512ac41dcd6508f280abaa2d54c90fc558b3ef..15c4c9c0f6910ea9a263d102fcbda2109c0d5c73 100644 --- a/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java +++ b/src/share/classes/java/util/concurrent/ConcurrentLinkedQueue.java @@ -485,19 +485,25 @@ public class ConcurrentLinkedQueue extends AbstractQueue * @return {@code true} if this queue changed as a result of the call */ public boolean remove(Object o) { - if (o == null) return false; - Node pred = null; - for (Node p = first(); p != null; p = succ(p)) { - E item = p.item; - if (item != null && - o.equals(item) && - p.casItem(item, null)) { - Node next = succ(p); - if (pred != null && next != null) + if (o != null) { + Node next, pred = null; + for (Node p = first(); p != null; pred = p, p = next) { + boolean removed = false; + E item = p.item; + if (item != null) { + if (!o.equals(item)) { + next = succ(p); + continue; + } + removed = p.casItem(item, null); + } + + next = succ(p); + if (pred != null && next != null) // unlink pred.casNext(p, next); - return true; + if (removed) + return true; } - pred = p; } return false; } diff --git a/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java b/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java new file mode 100644 index 0000000000000000000000000000000000000000..fd1e52d197b88586c20ff691330ead269b298a51 --- /dev/null +++ b/test/java/util/concurrent/ConcurrentLinkedQueue/RemoveLeak.java @@ -0,0 +1,60 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/* + * This file is available under and governed by the GNU General Public + * License version 2 only, as published by the Free Software Foundation. + * However, the following notice accompanied the original version of this + * file: + * + * Written by Martin Buchholz with assistance from members of JCP + * JSR-166 Expert Group and released to the public domain, as + * explained at http://creativecommons.org/publicdomain/zero/1.0/ + */ + +/* + * @test + * @bug 8054446 8137184 8137185 + * @summary Regression test for memory leak in remove(Object) + * @run main/othervm -Xmx2200k RemoveLeak + */ + +import java.util.concurrent.ConcurrentLinkedQueue; + +public class RemoveLeak { + public static void main(String[] args) { + int i = 0; + // Without bug fix, OutOfMemoryError was observed at iteration 65120 + int iterations = 10 * 65120; + try { + ConcurrentLinkedQueue queue = new ConcurrentLinkedQueue<>(); + queue.add(0L); + while (i++ < iterations) { + queue.add(1L); + queue.remove(1L); + } + } catch (Error t) { + System.err.printf("failed at iteration %d/%d%n", i, iterations); + throw t; + } + } +}