8344882: (bf) Temporary direct buffers should not count against the upper limit on direct buffer memory

Reviewed-by: alanb
This commit is contained in:
Brian Burkhalter 2024-11-27 16:14:03 +00:00
parent 75f3ec77e4
commit 0312694c46
5 changed files with 38 additions and 11 deletions

View File

@ -847,6 +847,11 @@ public abstract sealed class Buffer
return new HeapByteBuffer(hb, -1, 0, capacity, capacity, offset, segment); return new HeapByteBuffer(hb, -1, 0, capacity, capacity, offset, segment);
} }
@Override
public ByteBuffer newDirectByteBuffer(long addr, int cap) {
return new DirectByteBuffer(addr, cap);
}
@ForceInline @ForceInline
@Override @Override
public Object getBufferBase(Buffer buffer) { public Object getBufferBase(Buffer buffer) {

View File

@ -159,9 +159,10 @@ class Direct$Type$Buffer$RW$$BO$
} }
// Invoked only by JNI: NewDirectByteBuffer(void*, long) // Invoked only by JNI: NewDirectByteBuffer(void*, long)
// and JavaNioAccess.newDirectByteBuffer(int).
// The long-valued capacity is restricted to int range. // 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); super(-1, 0, checkCapacity(cap), (int)cap, null);
address = addr; address = addr;
cleaner = null; cleaner = null;

View File

@ -67,6 +67,11 @@ public interface JavaNioAccess {
*/ */
ByteBuffer newHeapByteBuffer(byte[] hb, int offset, int capacity, MemorySegment segment); 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}. * Used by {@code jdk.internal.foreign.Utils}.
*/ */

View File

@ -36,11 +36,15 @@ import java.util.Collection;
import java.util.Iterator; import java.util.Iterator;
import java.util.Set; import java.util.Set;
import jdk.internal.access.JavaNioAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.TerminatingThreadLocal; import jdk.internal.misc.TerminatingThreadLocal;
import jdk.internal.misc.Unsafe; import jdk.internal.misc.Unsafe;
public class Util { public class Util {
private static final JavaNioAccess NIO_ACCESS = SharedSecrets.getJavaNioAccess();
// -- Caches -- // -- Caches --
// The number of temp buffers in our pool // 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 // to remove the buffer from the cache (as this method does
// below) given that we won't put the new buffer in the cache. // below) given that we won't put the new buffer in the cache.
if (isBufferTooLarge(size)) { if (isBufferTooLarge(size)) {
return ByteBuffer.allocateDirect(size); long addr = unsafe.allocateMemory(size);
return NIO_ACCESS.newDirectByteBuffer(addr, size);
} }
BufferCache cache = bufferCache.get(); BufferCache cache = bufferCache.get();
@ -236,7 +241,8 @@ public class Util {
buf = cache.removeFirst(); buf = cache.removeFirst();
free(buf); 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, public static ByteBuffer getTemporaryAlignedDirectBuffer(int size,
int alignment) { int alignment) {
if (isBufferTooLarge(size)) { if (isBufferTooLarge(size)) {
return ByteBuffer.allocateDirect(size + alignment - 1) return getTemporaryDirectBuffer(size + alignment - 1)
.alignedSlice(alignment); .alignedSlice(alignment);
} }
BufferCache cache = bufferCache.get(); BufferCache cache = bufferCache.get();
@ -263,8 +269,8 @@ public class Util {
free(buf); free(buf);
} }
} }
return ByteBuffer.allocateDirect(size + alignment - 1) return getTemporaryDirectBuffer(size + alignment - 1)
.alignedSlice(alignment); .alignedSlice(alignment);
} }
/** /**
@ -274,12 +280,23 @@ public class Util {
offerFirstTemporaryDirectBuffer(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 * 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 * returning to the cache then insert it at the start so that it is
* likely to be returned by a subsequent call to getTemporaryDirectBuffer. * likely to be returned by a subsequent call to getTemporaryDirectBuffer.
*/ */
static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) { static void offerFirstTemporaryDirectBuffer(ByteBuffer buf) {
buf = unwrapIfAlignedSlice(buf);
// If the buffer is too large for the cache we don't have to // If the buffer is too large for the cache we don't have to
// check the cache. We'll just free it. // check the cache. We'll just free it.
if (isBufferTooLarge(buf)) { if (isBufferTooLarge(buf)) {
@ -302,6 +319,8 @@ public class Util {
* cache in same order that they were obtained. * cache in same order that they were obtained.
*/ */
static void offerLastTemporaryDirectBuffer(ByteBuffer buf) { static void offerLastTemporaryDirectBuffer(ByteBuffer buf) {
buf = unwrapIfAlignedSlice(buf);
// If the buffer is too large for the cache we don't have to // If the buffer is too large for the cache we don't have to
// check the cache. We'll just free it. // check the cache. We'll just free it.
if (isBufferTooLarge(buf)) { if (isBufferTooLarge(buf)) {
@ -321,7 +340,7 @@ public class Util {
* Frees the memory for the given direct buffer * Frees the memory for the given direct buffer
*/ */
private static void free(ByteBuffer buf) { private static void free(ByteBuffer buf) {
((DirectBuffer)buf).cleaner().clean(); unsafe.freeMemory(((DirectBuffer)buf).address());
} }

View File

@ -69,6 +69,3 @@ java/util/Properties/StoreReproducibilityTest.java 0000000 generic-all
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/ImplementationVersion/ImplVersionTest.java 0000000 generic-all
javax/management/remote/mandatory/version/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