8344882: (bf) Temporary direct buffers should not count against the upper limit on direct buffer memory
Reviewed-by: alanb
This commit is contained in:
parent
75f3ec77e4
commit
0312694c46
@ -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) {
|
||||||
|
@ -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;
|
||||||
|
@ -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}.
|
||||||
*/
|
*/
|
||||||
|
@ -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());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
|
||||||
|
Loading…
Reference in New Issue
Block a user