From 0312694c46b4fb3455cde2e4d1f8746ad4df8548 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Wed, 27 Nov 2024 16:14:03 +0000 Subject: [PATCH] 8344882: (bf) Temporary direct buffers should not count against the upper limit on direct buffer memory Reviewed-by: alanb --- .../share/classes/java/nio/Buffer.java | 5 +++ .../java/nio/Direct-X-Buffer.java.template | 3 +- .../jdk/internal/access/JavaNioAccess.java | 5 +++ .../share/classes/sun/nio/ch/Util.java | 33 +++++++++++++++---- test/jdk/ProblemList-Virtual.txt | 3 -- 5 files changed, 38 insertions(+), 11 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 39e0ff642a4..c0c2cfe80e7 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -847,6 +847,11 @@ public abstract sealed class Buffer return new HeapByteBuffer(hb, -1, 0, capacity, capacity, offset, segment); } + @Override + public ByteBuffer newDirectByteBuffer(long addr, int cap) { + return new DirectByteBuffer(addr, cap); + } + @ForceInline @Override public Object getBufferBase(Buffer buffer) { diff --git a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template index dac9abbf620..0da1dc66a9a 100644 --- a/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template +++ b/src/java.base/share/classes/java/nio/Direct-X-Buffer.java.template @@ -159,9 +159,10 @@ class Direct$Type$Buffer$RW$$BO$ } // Invoked only by JNI: NewDirectByteBuffer(void*, long) + // and JavaNioAccess.newDirectByteBuffer(int). // The long-valued capacity is restricted to int range. // - private Direct$Type$Buffer(long addr, long cap) { + Direct$Type$Buffer(long addr, long cap) { super(-1, 0, checkCapacity(cap), (int)cap, null); address = addr; cleaner = null; diff --git a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java index f2d2b7b5b65..431ffbdab53 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -67,6 +67,11 @@ public interface JavaNioAccess { */ ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment); + /** + * Used by {@code sun.nio.ch.Util}. + */ + ByteBuffer newDirectByteBuffer(long addr, int cap); + /** * Used by {@code jdk.internal.foreign.Utils}. */ diff --git a/src/java.base/share/classes/sun/nio/ch/Util.java b/src/java.base/share/classes/sun/nio/ch/Util.java index cf411008e43..24f1ee7d769 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -36,11 +36,15 @@ import java.util.Collection; import java.util.Iterator; import java.util.Set; +import jdk.internal.access.JavaNioAccess; +import jdk.internal.access.SharedSecrets; import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.Unsafe; public class Util { + private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess(); + // -- Caches -- // The number of temp buffers in our pool @@ -221,7 +225,8 @@ public class Util { // to remove the buffer from the cache (as this method does // below) given that we won't put the new buffer in the cache. if (isBufferTooLarge(size)) { - return ByteBuffer.allocateDirect(size); + long addr = unsafe.allocateMemory(size); + return NIO_ACCESS.newDirectByteBuffer(addr, size); } BufferCache cache = bufferCache.get(); @@ -236,7 +241,8 @@ public class Util { buf = cache.removeFirst(); free(buf); } - return ByteBuffer.allocateDirect(size); + long addr = unsafe.allocateMemory(size); + return NIO_ACCESS.newDirectByteBuffer(addr, size); } } @@ -247,8 +253,8 @@ public class Util { public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { if (isBufferTooLarge(size)) { - return ByteBuffer.allocateDirect(size + alignment - 1) - .alignedSlice(alignment); + return getTemporaryDirectBuffer(size + alignment - 1) + .alignedSlice(alignment); } BufferCache cache = bufferCache.get(); @@ -263,8 +269,8 @@ public class Util { free(buf); } } - return ByteBuffer.allocateDirect(size + alignment - 1) - .alignedSlice(alignment); + return getTemporaryDirectBuffer(size + alignment - 1) + .alignedSlice(alignment); } /** @@ -274,12 +280,23 @@ public class Util { offerFirstTemporaryDirectBuffer(buf); } + /** + * Return the underling byte buffer if the given byte buffer is + * an aligned slice. + */ + private static ByteBuffer unwrapIfAlignedSlice(ByteBuffer buf) { + var parent = (ByteBuffer) ((DirectBuffer) buf).attachment(); + return (parent != null) ? parent : buf; + } + /** * Releases a temporary buffer by returning to the cache or freeing it. If * returning to the cache then insert it at the start so that it is * likely to be returned by a subsequent call to getTemporaryDirectBuffer. */ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { + buf = unwrapIfAlignedSlice(buf); + // If the buffer is too large for the cache we don't have to // check the cache. We'll just free it. if (isBufferTooLarge(buf)) { @@ -302,6 +319,8 @@ public class Util { * cache in same order that they were obtained. */ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { + buf = unwrapIfAlignedSlice(buf); + // If the buffer is too large for the cache we don't have to // check the cache. We'll just free it. if (isBufferTooLarge(buf)) { @@ -321,7 +340,7 @@ public class Util { * Frees the memory for the given direct buffer */ private static void free(ByteBuffer buf) { - ((DirectBuffer)buf).cleaner().clean(); + unsafe.freeMemory(((DirectBuffer)buf).address()); } diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index b97e444ab36..d7692b578cd 100644 --- a/test/jdk/ProblemList-Virtual.txt +++ b/test/jdk/ProblemList-Virtual.txt @@ -69,6 +69,3 @@ java/util/Properties/StoreReproducibilityTest.java 0000000 generic-all java/util/Properties/StoreReproducibilityTest.java 0000000 generic-all javax/management/ImplementationVersion/ImplVersionTest.java 0000000 generic-all javax/management/remote/mandatory/version/ImplVersionTest.java 0000000 generic-all - -# Direct buffer memory allocated before test launch -java/nio/Buffer/LimitDirectMemory.java 8342849 generic-all