From 5640acb77be751509c5d2eee4703046dcaa05b57 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Fri, 22 Nov 2024 14:06:01 -0800 Subject: [PATCH 1/7] 8344882: (bf) Temporary direct buffers should not count against the upper limit on direct buffer memory --- .../share/classes/java/nio/Buffer.java | 5 ++++ .../java/nio/Direct-X-Buffer.java.template | 30 ++++++++++++++----- .../jdk/internal/access/JavaNioAccess.java | 5 ++++ .../share/classes/sun/nio/ch/Util.java | 12 +++++--- test/jdk/ProblemList-Virtual.txt | 3 -- 5 files changed, 40 insertions(+), 15 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 39e0ff642a44a..5eac72274de6e 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 ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemoryS return new HeapByteBuffer(hb, -1, 0, capacity, capacity, offset, segment); } + @Override + public ByteBuffer allocateDirectTemporary(int cap) { + return new DirectByteBuffer(cap, true); + } + @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 dac9abbf620a6..4476087440800 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 @@ -39,7 +39,9 @@ import jdk.internal.misc.ScopedMemoryAccess.ScopedAccessError; import jdk.internal.misc.VM; import jdk.internal.ref.Cleaner; import sun.nio.ch.DirectBuffer; - +#if[byte] +import jdk.internal.vm.annotation.Stable; +#end[byte] #if[rw] sealed @@ -72,14 +74,18 @@ class Direct$Type$Buffer$RW$$BO$ // Cached unaligned-access capability static final boolean UNALIGNED = Bits.unaligned(); - private record Deallocator(long address, long size, int capacity) implements Runnable { + private @Stable boolean temporary; // defaults to false + + private record Deallocator(long address, long size, int capacity, + boolean temporary) implements Runnable { private Deallocator { assert address != 0; } public void run() { UNSAFE.freeMemory(address); - Bits.unreserveMemory(size, capacity); + if (!temporary) + Bits.unreserveMemory(size, capacity); } } @@ -99,19 +105,22 @@ class Direct$Type$Buffer$RW$$BO$ // Primary constructor // - Direct$Type$Buffer$RW$(int cap) { // package-private + Direct$Type$Buffer$RW$(int cap, boolean temporary) { // package-private #if[rw] super(-1, 0, cap, cap, null); + this.temporary = temporary; boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); - Bits.reserveMemory(size, cap); + if (!temporary) + Bits.reserveMemory(size, cap); long base = 0; try { base = UNSAFE.allocateMemory(size); } catch (OutOfMemoryError x) { - Bits.unreserveMemory(size, cap); + if (!temporary) + Bits.unreserveMemory(size, cap); throw x; } UNSAFE.setMemory(base, size, (byte) 0); @@ -122,11 +131,12 @@ class Direct$Type$Buffer$RW$$BO$ address = base; } try { - cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); + cleaner = Cleaner.create(this, new Deallocator(base, size, cap, temporary)); } catch (Throwable t) { // Prevent leak if the Deallocator or Cleaner fail for any reason UNSAFE.freeMemory(base); - Bits.unreserveMemory(size, cap); + if (!temporary) + Bits.unreserveMemory(size, cap); throw t; } att = null; @@ -136,6 +146,10 @@ class Direct$Type$Buffer$RW$$BO$ #end[rw] } + Direct$Type$Buffer$RW$(int cap) { // package-private + this(cap, false); + } + #if[rw] // Invoked to construct a direct ByteBuffer referring to the block of 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 f2d2b7b5b65e6..0faed1808e603 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 allocateDirectTemporary(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 cf411008e43b8..4c57d292b5014 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.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,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { // 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); + return NIO_ACCESS.allocateDirectTemporary(size); } BufferCache cache = bufferCache.get(); @@ -236,7 +240,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { buf = cache.removeFirst(); free(buf); } - return ByteBuffer.allocateDirect(size); + return NIO_ACCESS.allocateDirectTemporary(size); } } @@ -247,7 +251,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { if (isBufferTooLarge(size)) { - return ByteBuffer.allocateDirect(size + alignment - 1) + return NIO_ACCESS.allocateDirectTemporary(size + alignment - 1) .alignedSlice(alignment); } @@ -263,7 +267,7 @@ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, free(buf); } } - return ByteBuffer.allocateDirect(size + alignment - 1) + return NIO_ACCESS.allocateDirectTemporary(size + alignment - 1) .alignedSlice(alignment); } diff --git a/test/jdk/ProblemList-Virtual.txt b/test/jdk/ProblemList-Virtual.txt index b97e444ab367b..d7692b578cd04 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 From b68ee5f0fca6d11c9c630c0d2cfd8a69d5891018 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 25 Nov 2024 10:47:56 -0800 Subject: [PATCH 2/7] 8344882: Do not create Cleaner for temporary buffers --- .../java/nio/Direct-X-Buffer.java.template | 24 +++++++++---------- .../share/classes/sun/nio/ch/Util.java | 2 +- 2 files changed, 13 insertions(+), 13 deletions(-) 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 4476087440800..4de087a01df2f 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 @@ -76,16 +76,14 @@ class Direct$Type$Buffer$RW$$BO$ private @Stable boolean temporary; // defaults to false - private record Deallocator(long address, long size, int capacity, - boolean temporary) implements Runnable { + private record Deallocator(long address, long size, int capacity) implements Runnable { private Deallocator { assert address != 0; } public void run() { UNSAFE.freeMemory(address); - if (!temporary) - Bits.unreserveMemory(size, capacity); + Bits.unreserveMemory(size, capacity); } } @@ -130,14 +128,16 @@ class Direct$Type$Buffer$RW$$BO$ } else { address = base; } - try { - cleaner = Cleaner.create(this, new Deallocator(base, size, cap, temporary)); - } catch (Throwable t) { - // Prevent leak if the Deallocator or Cleaner fail for any reason - UNSAFE.freeMemory(base); - if (!temporary) - Bits.unreserveMemory(size, cap); - throw t; + if (!temporary) { + try { + cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); + } catch (Throwable t) { + // Prevent leak if the Deallocator or Cleaner fail for any reason + UNSAFE.freeMemory(base); + throw t; + } + } else { // temporary + cleaner = null; } att = null; #else[rw] 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 4c57d292b5014..10aaa8bc95a0d 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -325,7 +325,7 @@ static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { * Frees the memory for the given direct buffer */ private static void free(ByteBuffer buf) { - ((DirectBuffer)buf).cleaner().clean(); + unsafe.freeMemory(((DirectBuffer)buf).address()); } From 9d84aa9cfd718265c72e26eff9434f8817d25d80 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 25 Nov 2024 11:17:06 -0800 Subject: [PATCH 3/7] 8344882: Remove DirectBuffer.temporary; rename JavaNioAccess temporary direct buffer allocation method --- src/java.base/share/classes/java/nio/Buffer.java | 2 +- .../share/classes/java/nio/Direct-X-Buffer.java.template | 3 --- .../share/classes/jdk/internal/access/JavaNioAccess.java | 2 +- src/java.base/share/classes/sun/nio/ch/Util.java | 8 ++++---- 4 files changed, 6 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 5eac72274de6e..95f9464396cfa 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -848,7 +848,7 @@ public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemoryS } @Override - public ByteBuffer allocateDirectTemporary(int cap) { + public ByteBuffer allocateTemporaryDirectBuffer(int cap) { return new DirectByteBuffer(cap, true); } 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 4de087a01df2f..a370834dd1bc1 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 @@ -74,8 +74,6 @@ class Direct$Type$Buffer$RW$$BO$ // Cached unaligned-access capability static final boolean UNALIGNED = Bits.unaligned(); - private @Stable boolean temporary; // defaults to false - private record Deallocator(long address, long size, int capacity) implements Runnable { private Deallocator { assert address != 0; @@ -106,7 +104,6 @@ class Direct$Type$Buffer$RW$$BO$ Direct$Type$Buffer$RW$(int cap, boolean temporary) { // package-private #if[rw] super(-1, 0, cap, cap, null); - this.temporary = temporary; boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); 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 0faed1808e603..e526ec91667b6 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -70,7 +70,7 @@ public interface JavaNioAccess { /** * Used by {@code sun.nio.ch.Util}. */ - ByteBuffer allocateDirectTemporary(int cap); + ByteBuffer allocateTemporaryDirectBuffer(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 10aaa8bc95a0d..448081e72936c 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -225,7 +225,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { // 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 NIO_ACCESS.allocateDirectTemporary(size); + return NIO_ACCESS.allocateTemporaryDirectBuffer(size); } BufferCache cache = bufferCache.get(); @@ -240,7 +240,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { buf = cache.removeFirst(); free(buf); } - return NIO_ACCESS.allocateDirectTemporary(size); + return NIO_ACCESS.allocateTemporaryDirectBuffer(size); } } @@ -251,7 +251,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { if (isBufferTooLarge(size)) { - return NIO_ACCESS.allocateDirectTemporary(size + alignment - 1) + return NIO_ACCESS.allocateTemporaryDirectBuffer(size + alignment - 1) .alignedSlice(alignment); } @@ -267,7 +267,7 @@ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, free(buf); } } - return NIO_ACCESS.allocateDirectTemporary(size + alignment - 1) + return NIO_ACCESS.allocateTemporaryDirectBuffer(size + alignment - 1) .alignedSlice(alignment); } From 4e4cdbb3887db3df462aed2592b851bb2ddb2f76 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Mon, 25 Nov 2024 11:52:49 -0800 Subject: [PATCH 4/7] 8344882: Remove vestigial import of Stable annotation --- .../share/classes/java/nio/Direct-X-Buffer.java.template | 3 --- 1 file changed, 3 deletions(-) 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 a370834dd1bc1..846363acdf2ba 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 @@ -39,9 +39,6 @@ import jdk.internal.misc.ScopedMemoryAccess.ScopedAccessError; import jdk.internal.misc.VM; import jdk.internal.ref.Cleaner; import sun.nio.ch.DirectBuffer; -#if[byte] -import jdk.internal.vm.annotation.Stable; -#end[byte] #if[rw] sealed From 1d7588a5144e9b449c8b030a94bba885fa52c1e0 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 26 Nov 2024 08:35:41 -0800 Subject: [PATCH 5/7] 8344882: Remove local field "temporary" by using an alternate constructor --- .../share/classes/java/nio/Buffer.java | 5 +-- .../java/nio/Direct-X-Buffer.java.template | 33 ++++++++----------- .../jdk/internal/access/JavaNioAccess.java | 2 +- .../share/classes/sun/nio/ch/Util.java | 8 ++--- 4 files changed, 21 insertions(+), 27 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index 95f9464396cfa..c1e37aef35cba 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -848,8 +848,9 @@ public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemoryS } @Override - public ByteBuffer allocateTemporaryDirectBuffer(int cap) { - return new DirectByteBuffer(cap, true); + public ByteBuffer newDirectByteBuffer(int cap) { + long addr = UNSAFE.allocateMemory(cap); + return new DirectByteBuffer(addr, cap); } @ForceInline 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 846363acdf2ba..0da1dc66a9a37 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 @@ -40,6 +40,7 @@ import jdk.internal.misc.VM; import jdk.internal.ref.Cleaner; import sun.nio.ch.DirectBuffer; + #if[rw] sealed #else[rw] @@ -98,21 +99,19 @@ class Direct$Type$Buffer$RW$$BO$ // Primary constructor // - Direct$Type$Buffer$RW$(int cap, boolean temporary) { // package-private + Direct$Type$Buffer$RW$(int cap) { // package-private #if[rw] super(-1, 0, cap, cap, null); boolean pa = VM.isDirectMemoryPageAligned(); int ps = Bits.pageSize(); long size = Math.max(1L, (long)cap + (pa ? ps : 0)); - if (!temporary) - Bits.reserveMemory(size, cap); + Bits.reserveMemory(size, cap); long base = 0; try { base = UNSAFE.allocateMemory(size); } catch (OutOfMemoryError x) { - if (!temporary) - Bits.unreserveMemory(size, cap); + Bits.unreserveMemory(size, cap); throw x; } UNSAFE.setMemory(base, size, (byte) 0); @@ -122,16 +121,13 @@ class Direct$Type$Buffer$RW$$BO$ } else { address = base; } - if (!temporary) { - try { - cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); - } catch (Throwable t) { - // Prevent leak if the Deallocator or Cleaner fail for any reason - UNSAFE.freeMemory(base); - throw t; - } - } else { // temporary - cleaner = null; + try { + cleaner = Cleaner.create(this, new Deallocator(base, size, cap)); + } catch (Throwable t) { + // Prevent leak if the Deallocator or Cleaner fail for any reason + UNSAFE.freeMemory(base); + Bits.unreserveMemory(size, cap); + throw t; } att = null; #else[rw] @@ -140,10 +136,6 @@ class Direct$Type$Buffer$RW$$BO$ #end[rw] } - Direct$Type$Buffer$RW$(int cap) { // package-private - this(cap, false); - } - #if[rw] // Invoked to construct a direct ByteBuffer referring to the block of @@ -167,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 e526ec91667b6..e1668b4dec8f5 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -70,7 +70,7 @@ public interface JavaNioAccess { /** * Used by {@code sun.nio.ch.Util}. */ - ByteBuffer allocateTemporaryDirectBuffer(int cap); + ByteBuffer newDirectByteBuffer(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 448081e72936c..719ae1c8e1e04 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -225,7 +225,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { // 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 NIO_ACCESS.allocateTemporaryDirectBuffer(size); + return NIO_ACCESS.newDirectByteBuffer(size); } BufferCache cache = bufferCache.get(); @@ -240,7 +240,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { buf = cache.removeFirst(); free(buf); } - return NIO_ACCESS.allocateTemporaryDirectBuffer(size); + return NIO_ACCESS.newDirectByteBuffer(size); } } @@ -251,7 +251,7 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { if (isBufferTooLarge(size)) { - return NIO_ACCESS.allocateTemporaryDirectBuffer(size + alignment - 1) + return NIO_ACCESS.newDirectByteBuffer(size + alignment - 1) .alignedSlice(alignment); } @@ -267,7 +267,7 @@ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, free(buf); } } - return NIO_ACCESS.allocateTemporaryDirectBuffer(size + alignment - 1) + return NIO_ACCESS.newDirectByteBuffer(size + alignment - 1) .alignedSlice(alignment); } From c27de5a36d4dbf9d57b26a3b910a0409654e8858 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 26 Nov 2024 08:55:55 -0800 Subject: [PATCH 6/7] 8344882: Make allocate+free be only in Util --- src/java.base/share/classes/java/nio/Buffer.java | 3 +-- .../classes/jdk/internal/access/JavaNioAccess.java | 2 +- src/java.base/share/classes/sun/nio/ch/Util.java | 14 ++++++++------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/java.base/share/classes/java/nio/Buffer.java b/src/java.base/share/classes/java/nio/Buffer.java index c1e37aef35cba..c0c2cfe80e7f0 100644 --- a/src/java.base/share/classes/java/nio/Buffer.java +++ b/src/java.base/share/classes/java/nio/Buffer.java @@ -848,8 +848,7 @@ public ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemoryS } @Override - public ByteBuffer newDirectByteBuffer(int cap) { - long addr = UNSAFE.allocateMemory(cap); + public ByteBuffer newDirectByteBuffer(long addr, int cap) { return new DirectByteBuffer(addr, cap); } 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 e1668b4dec8f5..431ffbdab5378 100644 --- a/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java +++ b/src/java.base/share/classes/jdk/internal/access/JavaNioAccess.java @@ -70,7 +70,7 @@ public interface JavaNioAccess { /** * Used by {@code sun.nio.ch.Util}. */ - ByteBuffer newDirectByteBuffer(int cap); + 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 719ae1c8e1e04..7736db11eede0 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -225,7 +225,8 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { // 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 NIO_ACCESS.newDirectByteBuffer(size); + long addr = unsafe.allocateMemory(size); + return NIO_ACCESS.newDirectByteBuffer(addr, size); } BufferCache cache = bufferCache.get(); @@ -240,7 +241,8 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { buf = cache.removeFirst(); free(buf); } - return NIO_ACCESS.newDirectByteBuffer(size); + long addr = unsafe.allocateMemory(size); + return NIO_ACCESS.newDirectByteBuffer(addr, size); } } @@ -251,8 +253,8 @@ public static ByteBuffer getTemporaryDirectBuffer(int size) { public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, int alignment) { if (isBufferTooLarge(size)) { - return NIO_ACCESS.newDirectByteBuffer(size + alignment - 1) - .alignedSlice(alignment); + return getTemporaryDirectBuffer(size + alignment - 1) + .alignedSlice(alignment); } BufferCache cache = bufferCache.get(); @@ -267,8 +269,8 @@ public static ByteBuffer getTemporaryAlignedDirectBuffer(int size, free(buf); } } - return NIO_ACCESS.newDirectByteBuffer(size + alignment - 1) - .alignedSlice(alignment); + return getTemporaryDirectBuffer(size + alignment - 1) + .alignedSlice(alignment); } /** From 80d6551dcfd071dd6f86c4224f2d2be544735426 Mon Sep 17 00:00:00 2001 From: Brian Burkhalter Date: Tue, 26 Nov 2024 10:48:19 -0800 Subject: [PATCH 7/7] 8344882: If the buffer is a slice, free it's parent's address --- src/java.base/share/classes/sun/nio/ch/Util.java | 13 +++++++++++++ 1 file changed, 13 insertions(+) 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 7736db11eede0..24f1ee7d76901 100644 --- a/src/java.base/share/classes/sun/nio/ch/Util.java +++ b/src/java.base/share/classes/sun/nio/ch/Util.java @@ -280,12 +280,23 @@ public static void releaseTemporaryDirectBuffer(ByteBuffer buf) { 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)) { @@ -308,6 +319,8 @@ static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { * 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)) {