--- old/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2016-03-06 12:29:58.138511313 +0100 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2016-03-06 12:29:58.057512698 +0100 @@ -30,7 +30,7 @@ import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.*; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; -import jdk.internal.ref.Cleaner; +import jdk.internal.ref.CleanerFactory; /** * The JVM interface for the method handles package is all here. @@ -68,10 +68,12 @@ static CallSiteContext make(CallSite cs) { final CallSiteContext newContext = new CallSiteContext(); - // Cleaner is attached to CallSite instance and it clears native structures allocated for CallSite context. - // Though the CallSite can become unreachable, its Context is retained by the Cleaner instance (which is - // referenced from Cleaner class) until cleanup is performed. - Cleaner.create(cs, newContext); + // CallSite instance is tracked by a Cleanable which clears native + // structures allocated for CallSite context. Though the CallSite can + // become unreachable, its Context is retained by the Cleanable instance + // (which is referenced from Cleaner instance which is referenced from + // CleanerFactory class) until cleanup is performed. + CleanerFactory.cleaner().register(cs, newContext); return newContext; } --- old/src/java.base/share/classes/java/lang/ref/Cleaner.java 2016-03-06 12:29:58.382507143 +0100 +++ new/src/java.base/share/classes/java/lang/ref/Cleaner.java 2016-03-06 12:29:58.300508544 +0100 @@ -25,10 +25,11 @@ package java.lang.ref; +import jdk.internal.ref.CleanerImpl; + import java.util.Objects; import java.util.concurrent.ThreadFactory; - -import jdk.internal.ref.CleanerImpl; +import java.util.function.Function; /** * {@code Cleaner} manages a set of object references and corresponding cleaning actions. @@ -135,7 +136,12 @@ final CleanerImpl impl; static { - CleanerImpl.setCleanerImplAccess((Cleaner c) -> c.impl); + CleanerImpl.setCleanerImplAccess(new Function() { + @Override + public CleanerImpl apply(Cleaner cleaner) { + return cleaner.impl; + } + }); } /** --- old/src/java.base/share/classes/jdk/internal/misc/InnocuousThread.java 2016-03-06 12:29:58.700501707 +0100 +++ new/src/java.base/share/classes/jdk/internal/misc/InnocuousThread.java 2016-03-06 12:29:58.579503775 +0100 @@ -128,8 +128,12 @@ } final ThreadGroup root = group; INNOCUOUSTHREADGROUP = AccessController.doPrivileged( - (PrivilegedAction) () -> - { return new ThreadGroup(root, "InnocuousThreadGroup"); }); + new PrivilegedAction() { + @Override + public ThreadGroup run() { + return new ThreadGroup(root, "InnocuousThreadGroup"); + } + }); } catch (Exception e) { throw new Error(e); } --- old/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-03-06 12:29:58.910498117 +0100 +++ new/src/java.base/share/classes/jdk/internal/ref/CleanerImpl.java 2016-03-06 12:29:58.830499484 +0100 @@ -31,6 +31,7 @@ import java.security.AccessController; import java.security.PrivilegedAction; import java.util.concurrent.ThreadFactory; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Function; import jdk.internal.misc.InnocuousThread; @@ -39,7 +40,7 @@ * CleanerImpl manages a set of object references and corresponding cleaning actions. * CleanerImpl provides the functionality of {@link java.lang.ref.Cleaner}. */ -public final class CleanerImpl { +public final class CleanerImpl implements Runnable { /** * An object to access the CleanerImpl from a Cleaner; set by Cleaner init. @@ -103,7 +104,7 @@ } // schedule a nop cleaning action for the cleaner, so the associated thread // will continue to run at least until the cleaner is reclaimable. - new PhantomCleanableRef(cleaner, cleaner, () -> {}); + new CleanerCleanable(cleaner); if (threadFactory == null) { threadFactory = CleanerImpl.InnocuousThreadFactory.factory(); @@ -112,7 +113,7 @@ // now that there's at least one cleaning action, for the cleaner, // we can start the associated thread, which runs until // all cleaning actions have been run. - Thread thread = threadFactory.newThread(this::run); + Thread thread = threadFactory.newThread(this); thread.setDaemon(true); thread.start(); } @@ -128,7 +129,8 @@ * If the thread is a ManagedLocalsThread, the threadlocals * are erased before each cleanup */ - private void run() { + @Override + public void run() { Thread t = Thread.currentThread(); InnocuousThread mlThread = (t instanceof InnocuousThread) ? (InnocuousThread) t @@ -147,10 +149,9 @@ if (ref != null) { ref.clean(); } - } catch (InterruptedException i) { - continue; // ignore the interruption } catch (Throwable e) { // ignore exceptions from the cleanup action + // (including interruption of cleanup thread) } } } @@ -320,14 +321,32 @@ return factory; } + final AtomicInteger cleanerThreadNumber = new AtomicInteger(); + public Thread newThread(Runnable r) { - return AccessController.doPrivileged((PrivilegedAction) () -> { - Thread t = new InnocuousThread(r); - t.setPriority(Thread.MAX_PRIORITY - 2); - t.setName("Cleaner-" + t.getId()); - return t; + return AccessController.doPrivileged(new PrivilegedAction() { + @Override + public Thread run() { + Thread t = new InnocuousThread(r); + t.setPriority(Thread.MAX_PRIORITY - 2); + t.setName("Cleaner-" + cleanerThreadNumber.getAndIncrement()); + return t; + } }); } } + /** + * A PhantomCleanable implementation for tracking the Cleaner itself. + */ + static final class CleanerCleanable extends PhantomCleanable { + CleanerCleanable(Cleaner cleaner) { + super(cleaner, cleaner); + } + + @Override + protected void performCleanup() { + // no action + } + } } --- old/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java 2016-03-06 12:29:59.244492407 +0100 +++ new/src/java.base/share/classes/sun/nio/ch/IOVecWrapper.java 2016-03-06 12:29:59.101494852 +0100 @@ -26,7 +26,7 @@ package sun.nio.ch; import java.nio.ByteBuffer; -import jdk.internal.ref.Cleaner; +import jdk.internal.ref.CleanerFactory; /** @@ -101,7 +101,7 @@ } if (wrapper == null) { wrapper = new IOVecWrapper(size); - Cleaner.create(wrapper, new Deallocator(wrapper.vecArray)); + CleanerFactory.cleaner().register(wrapper, new Deallocator(wrapper.vecArray)); cached.set(wrapper); } return wrapper; --- old/src/java.base/share/classes/sun/nio/ch/Util.java 2016-03-06 12:29:59.597486373 +0100 +++ new/src/java.base/share/classes/sun/nio/ch/Util.java 2016-03-06 12:29:59.454488817 +0100 @@ -33,7 +33,6 @@ import java.security.PrivilegedAction; import java.util.*; import jdk.internal.misc.Unsafe; -import jdk.internal.ref.Cleaner; import sun.security.action.GetPropertyAction; --- old/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java 2016-03-06 12:29:59.923480800 +0100 +++ new/src/java.base/share/classes/sun/nio/fs/NativeBuffer.java 2016-03-06 12:29:59.788483108 +0100 @@ -26,7 +26,9 @@ package sun.nio.fs; import jdk.internal.misc.Unsafe; -import jdk.internal.ref.Cleaner; +import jdk.internal.ref.CleanerFactory; + +import java.lang.ref.Cleaner; /** * A light-weight buffer in native memory. @@ -37,7 +39,7 @@ private final long address; private final int size; - private final Cleaner cleaner; + private final Cleaner.Cleanable cleanable; // optional "owner" to avoid copying // (only safe for use by thread-local caches) @@ -56,7 +58,7 @@ NativeBuffer(int size) { this.address = unsafe.allocateMemory(size); this.size = size; - this.cleaner = Cleaner.create(this, new Deallocator(address)); + this.cleanable = CleanerFactory.cleaner().register(this, new Deallocator(address)); } void release() { @@ -71,8 +73,8 @@ return size; } - Cleaner cleaner() { - return cleaner; + void free() { + cleanable.clean(); } // not synchronized; only safe for use by thread-local caches --- old/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java 2016-03-06 12:30:00.260475040 +0100 +++ new/src/java.base/share/classes/sun/nio/fs/NativeBuffers.java 2016-03-06 12:30:00.126477330 +0100 @@ -107,14 +107,14 @@ for (int i=0; i