--- old/src/java.base/share/classes/java/lang/ref/Cleaner.java 2017-10-31 23:27:34.856594904 +0100
+++ new/src/java.base/share/classes/java/lang/ref/Cleaner.java 2017-10-31 23:27:34.711597374 +0100
@@ -29,7 +29,11 @@
import java.util.Objects;
import java.util.concurrent.ThreadFactory;
+import java.util.function.Consumer;
import java.util.function.Function;
+import java.util.function.LongConsumer;
+import java.util.function.LongSupplier;
+import java.util.function.Supplier;
/**
* {@code Cleaner} manages a set of object references and corresponding cleaning actions.
@@ -234,4 +238,114 @@
void clean();
}
+ /**
+ * 1st registers an object then allocates a reference-valued resource by
+ * invoking resource allocator function and associates it with de-allocator
+ * function which will be called with the resource as cleaning action when
+ * the registered object becomes phantom reachable.
+ * Using this method (when applicable) is preferable to using
+ * {@link #register(Object, Runnable)}, because it ensures correct
+ * order of actions - 1st register the object, then allocate the resource -
+ * which prevents resource leaks in rare circumstances when registration fails
+ * because of insufficient heap memory. The resource allocator function still
+ * bares all the responsibility for either returning normally with the
+ * allocated resource or throwing an unchecked exception in which case the
+ * resource should not be allocated or should already be de-allocated, because
+ * in such case, the de-allocator function is not called.
+ * Refer to the API Note above for
+ * cautions about the behavior of cleaning actions.
+ *
+ * @param obj the object to monitor
+ * @param resourceAllocator the resource allocator function
+ * @param resourceDeallocator the resource de-allocator function, invoked as
+ * cleaning action with the allocated resource
+ * @param the type of resource
+ * @return a {@link CleanableResource} instance holding the allocated resource
+ * with associated de-allocator function as cleaning action
+ * @since 10
+ */
+ public CleanableResource createResource(
+ Object obj,
+ Supplier extends T> resourceAllocator,
+ Consumer super T> resourceDeallocator)
+ {
+ Objects.requireNonNull(obj, "obj");
+ Objects.requireNonNull(resourceAllocator, "resourceConstructor");
+ Objects.requireNonNull(resourceDeallocator, "resourceDestructor");
+ return new CleanerImpl.PhantomCleanableResource<>(obj, this, resourceAllocator, resourceDeallocator);
+ }
+
+ /**
+ * {@code CleanableResource} represents an object holding some reference
+ * valued resource and a cleaning action for the resource registered in a
+ * {@code Cleaner}.
+ *
+ * @since 10
+ *
+ * @param the type of allocated resource
+ */
+ public interface CleanableResource extends Cleanable {
+ /**
+ * Obtains the allocated resource.
+ *
+ * @return the allocated resource
+ * @throws IllegalStateException if the resource has already been
+ * {@link #clean() cleaned}
+ */
+ T value();
+ }
+
+ /**
+ * 1st registers an object then allocates a {@code long}-valued resource by
+ * invoking resource allocator function and associates it with de-allocator
+ * function which will be called with the resource as cleaning action when
+ * the registered object becomes phantom reachable.
+ * Using this method (when applicable) is preferable to using
+ * {@link #register(Object, Runnable)}, because it ensures correct
+ * order of actions - 1st register the object, then allocate the resource -
+ * which prevents resource leaks in rare circumstances when registration fails
+ * because of insufficient heap memory. The resource allocator function still
+ * bares all the responsibility for either returning normally with the
+ * allocated resource or throwing an unchecked exception in which case the
+ * resource should not be allocated or should already be de-allocated, because
+ * in such case, the de-allocator function is not called.
+ * Refer to the API Note above for
+ * cautions about the behavior of cleaning actions.
+ *
+ * @param obj the object to monitor
+ * @param resourceAllocator the resource allocator function
+ * @param resourceDeallocator the resource de-allocator function, invoked as
+ * cleaning action with the allocated resource
+ * @return a {@link LongCleanableResource} instance holding the allocated resource
+ * with associated de-allocator function as cleaning action
+ * @since 10
+ */
+ public LongCleanableResource createLongResource(
+ Object obj,
+ LongSupplier resourceAllocator,
+ LongConsumer resourceDeallocator)
+ {
+ Objects.requireNonNull(obj, "obj");
+ Objects.requireNonNull(resourceAllocator, "resourceConstructor");
+ Objects.requireNonNull(resourceDeallocator, "resourceDestructor");
+ return new CleanerImpl.PhantomLongCleanableResource(obj, this, resourceAllocator, resourceDeallocator);
+ }
+
+ /**
+ * {@code LongCleanableResource} represents an object holding some {@code long}
+ * valued resource and a cleaning action for the resource registered in a
+ * {@code Cleaner}.
+ *
+ * @since 10
+ */
+ public interface LongCleanableResource extends Cleanable {
+ /**
+ * Obtains the allocated resource.
+ *
+ * @return the allocated resource
+ * @throws IllegalStateException if the resource has already been
+ * {@link #clean() cleaned}
+ */
+ long value();
+ }
}
--- old/src/java.base/share/classes/java/util/zip/Deflater.java 2017-10-31 23:27:35.188589249 +0100
+++ new/src/java.base/share/classes/java/util/zip/Deflater.java 2017-10-31 23:27:35.068591293 +0100
@@ -25,6 +25,11 @@
package java.util.zip;
+import jdk.internal.ref.CleanerFactory;
+
+import java.lang.ref.Cleaner;
+import java.lang.ref.Reference;
+
/**
* This class provides support for general purpose compression using the
* popular ZLIB compression library. The ZLIB compression library was
@@ -67,6 +72,20 @@
* }
*
*
+ *
+ * @apiNote
+ * In earlier versions the {@link Object#finalize} method was overridden and
+ * specified to call the {@code end} method to close the {@code deflater} and
+ * release the resource when the instance becomes unreachable.
+ * The {@code finalize} method is no longer defined. The recommended cleanup
+ * for compressor is to explicitly call {@code end} method when it is no
+ * longer in use.
+ *
+ * @implNote
+ * The resource of the compressor will be released when the instance becomes
+ * phantom-reachable, if the {@code end} is not invoked explicitly.
+ *
+ *
* @see Inflater
* @author David Connelly
* @since 1.1
@@ -74,7 +93,7 @@
public
class Deflater {
- private final ZStreamRef zsRef;
+ private final Cleaner.LongCleanableResource zsRef;
private byte[] buf = new byte[0];
private int off, len;
private int level, strategy;
@@ -169,7 +188,11 @@
public Deflater(int level, boolean nowrap) {
this.level = level;
this.strategy = DEFAULT_STRATEGY;
- this.zsRef = new ZStreamRef(init(level, DEFAULT_STRATEGY, nowrap));
+ this.zsRef = CleanerFactory
+ .cleaner()
+ .createLongResource(this,
+ () -> init(level, DEFAULT_STRATEGY, nowrap),
+ Deflater::end);
}
/**
@@ -242,7 +265,8 @@
}
synchronized (zsRef) {
ensureOpen();
- setDictionary(zsRef.address(), b, off, len);
+ setDictionary(zsRef.value(), b, off, len);
+ Reference.reachabilityFence(this);
}
}
@@ -445,7 +469,8 @@
if (flush == NO_FLUSH || flush == SYNC_FLUSH ||
flush == FULL_FLUSH) {
int thisLen = this.len;
- int n = deflateBytes(zsRef.address(), b, off, len, flush);
+ int n = deflateBytes(zsRef.value(), b, off, len, flush);
+ Reference.reachabilityFence(this);
bytesWritten += n;
bytesRead += (thisLen - this.len);
return n;
@@ -461,7 +486,9 @@
public int getAdler() {
synchronized (zsRef) {
ensureOpen();
- return getAdler(zsRef.address());
+ int adler = getAdler(zsRef.value());
+ Reference.reachabilityFence(this);
+ return adler;
}
}
@@ -524,7 +551,8 @@
public void reset() {
synchronized (zsRef) {
ensureOpen();
- reset(zsRef.address());
+ reset(zsRef.value());
+ Reference.reachabilityFence(this);
finish = false;
finished = false;
off = len = 0;
@@ -534,43 +562,25 @@
/**
* Closes the compressor and discards any unprocessed input.
+ *
* This method should be called when the compressor is no longer
- * being used, but will also be called automatically by the
- * finalize() method. Once this method is called, the behavior
- * of the Deflater object is undefined.
+ * being used. Once this method is called, the behavior of the
+ * Deflater object is undefined.
*/
public void end() {
synchronized (zsRef) {
- long addr = zsRef.address();
- zsRef.clear();
- if (addr != 0) {
- end(addr);
- buf = null;
- }
+ zsRef.clean();
+ buf = null;
}
}
- /**
- * Closes the compressor when garbage is collected.
- *
- * @deprecated The {@code finalize} method has been deprecated.
- * Subclasses that override {@code finalize} in order to perform cleanup
- * should be modified to use alternative cleanup mechanisms and
- * to remove the overriding {@code finalize} method.
- * When overriding the {@code finalize} method, its implementation must explicitly
- * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
- * See the specification for {@link Object#finalize()} for further
- * information about migration options.
- */
- @Deprecated(since="9")
- protected void finalize() {
- end();
- }
-
private void ensureOpen() {
assert Thread.holdsLock(zsRef);
- if (zsRef.address() == 0)
+ try {
+ zsRef.value();
+ } catch (IllegalStateException e) {
throw new NullPointerException("Deflater has been closed");
+ }
}
private static native void initIDs();
--- old/src/java.base/share/classes/java/util/zip/Inflater.java 2017-10-31 23:27:35.524583525 +0100
+++ new/src/java.base/share/classes/java/util/zip/Inflater.java 2017-10-31 23:27:35.402585603 +0100
@@ -25,6 +25,11 @@
package java.util.zip;
+import jdk.internal.ref.CleanerFactory;
+
+import java.lang.ref.Cleaner;
+import java.lang.ref.Reference;
+
/**
* This class provides support for general purpose decompression using the
* popular ZLIB compression library. The ZLIB compression library was
@@ -66,6 +71,20 @@
* }
*
*
+ *
+ * @apiNote
+ * In earlier versions the {@link Object#finalize} method was overridden and
+ * specified to call the {@code end} method to close the {@code inflater} and
+ * release the resource when the instance becomes unreachable.
+ * The {@code finalize} method is no longer defined. The recommended cleanup
+ * for decompressor is to explicitly call {@code end} method when it is no
+ * longer in use.
+ *
+ * @implNote
+ * The resource of the decompressor will be released when the instance becomes
+ * phantom-reachable, if the {@code end} is not invoked explicitly.
+ *
+ *
* @see Deflater
* @author David Connelly
* @since 1.1
@@ -74,7 +93,7 @@
public
class Inflater {
- private final ZStreamRef zsRef;
+ private final Cleaner.LongCleanableResource zsRef;
private byte[] buf = defaultBuf;
private int off, len;
private boolean finished;
@@ -101,7 +120,9 @@
* @param nowrap if true then support GZIP compatible compression
*/
public Inflater(boolean nowrap) {
- zsRef = new ZStreamRef(init(nowrap));
+ this.zsRef = CleanerFactory
+ .cleaner()
+ .createLongResource(this, () -> init(nowrap), Inflater::end);
}
/**
@@ -165,7 +186,8 @@
}
synchronized (zsRef) {
ensureOpen();
- setDictionary(zsRef.address(), b, off, len);
+ setDictionary(zsRef.value(), b, off, len);
+ Reference.reachabilityFence(this);
needDict = false;
}
}
@@ -257,7 +279,8 @@
synchronized (zsRef) {
ensureOpen();
int thisLen = this.len;
- int n = inflateBytes(zsRef.address(), b, off, len);
+ int n = inflateBytes(zsRef.value(), b, off, len);
+ Reference.reachabilityFence(this);
bytesWritten += n;
bytesRead += (thisLen - this.len);
return n;
@@ -288,7 +311,9 @@
public int getAdler() {
synchronized (zsRef) {
ensureOpen();
- return getAdler(zsRef.address());
+ int adler = getAdler(zsRef.value());
+ Reference.reachabilityFence(this);
+ return adler;
}
}
@@ -350,7 +375,8 @@
public void reset() {
synchronized (zsRef) {
ensureOpen();
- reset(zsRef.address());
+ reset(zsRef.value());
+ Reference.reachabilityFence(this);
buf = defaultBuf;
finished = false;
needDict = false;
@@ -361,48 +387,24 @@
/**
* Closes the decompressor and discards any unprocessed input.
+ *
* This method should be called when the decompressor is no longer
- * being used, but will also be called automatically by the finalize()
- * method. Once this method is called, the behavior of the Inflater
- * object is undefined.
+ * being used. Once this method is called, the behavior of the
+ * Inflater object is undefined.
*/
public void end() {
synchronized (zsRef) {
- long addr = zsRef.address();
- zsRef.clear();
- if (addr != 0) {
- end(addr);
- buf = null;
- }
+ zsRef.clean();
+ buf = null;
}
}
- /**
- * Closes the decompressor when garbage is collected.
- *
- * @deprecated The {@code finalize} method has been deprecated.
- * Subclasses that override {@code finalize} in order to perform cleanup
- * should be modified to use alternative cleanup mechanisms and
- * to remove the overriding {@code finalize} method.
- * When overriding the {@code finalize} method, its implementation must explicitly
- * ensure that {@code super.finalize()} is invoked as described in {@link Object#finalize}.
- * See the specification for {@link Object#finalize()} for further
- * information about migration options.
- */
- @Deprecated(since="9")
- protected void finalize() {
- end();
- }
-
private void ensureOpen () {
assert Thread.holdsLock(zsRef);
- if (zsRef.address() == 0)
+ try {
+ zsRef.value();
+ } catch (IllegalStateException e) {
throw new NullPointerException("Inflater has been closed");
- }
-
- boolean ended() {
- synchronized (zsRef) {
- return zsRef.address() == 0;
}
}
--- old/src/java.base/share/classes/java/util/zip/InflaterInputStream.java 2017-10-31 23:27:35.854577904 +0100
+++ new/src/java.base/share/classes/java/util/zip/InflaterInputStream.java 2017-10-31 23:27:35.734579948 +0100
@@ -25,10 +25,15 @@
package java.util.zip;
+import jdk.internal.ref.CleanerFactory;
+
+import java.io.EOFException;
import java.io.FilterInputStream;
-import java.io.InputStream;
import java.io.IOException;
-import java.io.EOFException;
+import java.io.InputStream;
+import java.lang.ref.Cleaner;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
/**
* This class implements a stream filter for uncompressing data in the
@@ -60,6 +65,9 @@
// this flag is set to true after EOF has reached
private boolean reachEOF = false;
+ // in case this stream manages own Inflater, else null
+ private final Cleaner.CleanableResource infRes;
+
/**
* Check to make sure that this stream has not been closed
*/
@@ -85,8 +93,9 @@
} else if (size <= 0) {
throw new IllegalArgumentException("buffer size <= 0");
}
+ this.buf = new byte[size];
+ this.infRes = null; // uses specified/default decompressor
this.inf = inf;
- buf = new byte[size];
}
/**
@@ -110,6 +119,31 @@
usesDefaultInflater = true;
}
+ /**
+ * Creates a new input stream with a decompressor allocated by inflaterAllocator
+ * and deallocated by inflaterDeallocator and buffer size.
+ * @param in the input stream
+ * @param inflaterAllocator the inflater allocator function
+ * @param inflaterDeallocator the inflater de-allocator function
+ * @param size the input buffer size
+ */
+ InflaterInputStream(InputStream in,
+ Supplier inflaterAllocator,
+ Consumer inflaterDeallocator,
+ int size) {
+ super(in);
+ if (in == null) {
+ throw new NullPointerException();
+ } else if (size <= 0) {
+ throw new IllegalArgumentException("buffer size <= 0");
+ }
+ this.buf = new byte[size];
+ this.infRes = CleanerFactory
+ .cleaner()
+ .createResource(this, inflaterAllocator, inflaterDeallocator);
+ this.inf = infRes.value();
+ }
+
private byte[] singleByteBuf = new byte[1];
/**
@@ -227,7 +261,9 @@
*/
public void close() throws IOException {
if (!closed) {
- if (usesDefaultInflater)
+ if (infRes != null)
+ infRes.clean();
+ else if (usesDefaultInflater)
inf.end();
in.close();
closed = true;
--- old/src/java.base/share/classes/java/util/zip/ZipFile.java 2017-10-31 23:27:36.179572368 +0100
+++ new/src/java.base/share/classes/java/util/zip/ZipFile.java 2017-10-31 23:27:36.061574378 +0100
@@ -31,34 +31,37 @@
import java.io.EOFException;
import java.io.File;
import java.io.RandomAccessFile;
+import java.io.UncheckedIOException;
+import java.lang.ref.Cleaner;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.nio.file.attribute.BasicFileAttributes;
-import java.nio.file.Path;
import java.nio.file.Files;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Arrays;
+import java.util.Collections;
import java.util.Deque;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Iterator;
-import java.util.Map;
import java.util.Objects;
import java.util.NoSuchElementException;
+import java.util.Set;
import java.util.Spliterator;
import java.util.Spliterators;
import java.util.WeakHashMap;
+import java.util.function.Consumer;
+import java.util.function.Supplier;
import java.util.stream.Stream;
import java.util.stream.StreamSupport;
import jdk.internal.misc.JavaUtilZipFileAccess;
import jdk.internal.misc.SharedSecrets;
-import jdk.internal.misc.JavaIORandomAccessFileAccess;
import jdk.internal.misc.VM;
import jdk.internal.perf.PerfCounter;
+import jdk.internal.ref.CleanerFactory;
-import static java.util.zip.ZipConstants.*;
import static java.util.zip.ZipConstants64.*;
import static java.util.zip.ZipUtils.*;
@@ -69,6 +72,19 @@
* or method in this class will cause a {@link NullPointerException} to be
* thrown.
*
+ *
+ * @apiNote
+ * In earlier versions, the {@link Object#finalize} method was overridden and
+ * specified to close the ZipFile object and release its system resource when
+ * the instance becomes unreachable. The {@code finalize} method is no longer
+ * defined. The recommended cleanup for ZipFile object is to explicitly invoke
+ * {@code close} method when it is no longer in use, or use try-with-resources.
+ *
+ * @implNote
+ * The resources held by this object will be released when the instance becomes
+ * phantom-reachable, if the {@code close} is not invoked explicitly.
+ *
+ *
* @author David Connelly
* @since 1.1
*/
@@ -80,6 +96,15 @@
private Source zsrc;
private ZipCoder zc;
+ // The outstanding inputstreams that need to be closed
+ private final Set streams;
+
+ // List of cached Inflater objects for decompression
+ private final Deque inflaterCache;
+
+ // Cleanable reference to Source
+ private final Cleaner.CleanableResource