Skip to content

Commit

Permalink
Delay access to constructor and methods for DirectBuffers until first…
Browse files Browse the repository at this point in the history
… use (#932)
  • Loading branch information
theigl authored Dec 20, 2022
1 parent b6fd8f9 commit bb10a0b
Showing 1 changed file with 29 additions and 26 deletions.
55 changes: 29 additions & 26 deletions src/com/esotericsoftware/kryo/unsafe/UnsafeUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -90,29 +90,32 @@ public class UnsafeUtil {
booleanArrayBaseOffset = tempBooleanArrayBaseOffset;
unsafe = tempUnsafe;
}

// Constructor to be used for creation of ByteBuffers that use preallocated memory regions.
private static Constructor<? extends ByteBuffer> directByteBufferConstructor;
static {
ByteBuffer buffer = ByteBuffer.allocateDirect(1);
try {
directByteBufferConstructor = buffer.getClass().getDeclaredConstructor(long.class, int.class);
directByteBufferConstructor.setAccessible(true);
} catch (Exception ex) {
if (DEBUG) debug("kryo", "No direct ByteBuffer constructor is available.", ex);
directByteBufferConstructor = null;

// Use a static inner class to defer initialization of direct buffer methods until first use
private static final class DirectBuffers {
// Constructor to be used for creation of ByteBuffers that use pre-allocated memory regions.
private static Constructor<? extends ByteBuffer> directByteBufferConstructor;
static {
ByteBuffer buffer = ByteBuffer.allocateDirect(1);
try {
directByteBufferConstructor = buffer.getClass().getDeclaredConstructor(long.class, int.class);
directByteBufferConstructor.setAccessible(true);
} catch (Exception ex) {
if (DEBUG) debug("kryo", "No direct ByteBuffer constructor is available.", ex);
directByteBufferConstructor = null;
}
}
}

private static Method cleanerMethod, cleanMethod;
static {
try {
cleanerMethod = DirectBuffer.class.getMethod("cleaner");
cleanerMethod.setAccessible(true);
cleanMethod = cleanerMethod.getReturnType().getMethod("clean");
} catch (Exception ex) {
if (DEBUG) debug("kryo", "No direct ByteBuffer clean method is available.", ex);
cleanerMethod = null;
private static Method cleanerMethod, cleanMethod;
static {
try {
cleanerMethod = DirectBuffer.class.getMethod("cleaner");
cleanerMethod.setAccessible(true);
cleanMethod = cleanerMethod.getReturnType().getMethod("clean");
} catch (Exception ex) {
if (DEBUG) debug("kryo", "No direct ByteBuffer clean method is available.", ex);
cleanerMethod = null;
}
}
}

Expand All @@ -121,26 +124,26 @@ public class UnsafeUtil {
* @param size Size in bytes of the memory region.
* @throws UnsupportedOperationException if creating a ByteBuffer this way is not available. */
public static ByteBuffer newDirectBuffer (long address, int size) {
if (directByteBufferConstructor == null)
if (!isNewDirectBufferAvailable())
throw new UnsupportedOperationException("No direct ByteBuffer constructor is available.");
try {
return directByteBufferConstructor.newInstance(address, size);
return DirectBuffers.directByteBufferConstructor.newInstance(address, size);
} catch (Exception ex) {
throw new KryoException("Error creating a ByteBuffer at address: " + address, ex);
}
}

/** Returns true if {@link #newDirectBuffer(long, int)} can be called. */
public static boolean isNewDirectBufferAvailable () {
return directByteBufferConstructor != null;
return DirectBuffers.directByteBufferConstructor != null;
}

/** Release a direct buffer immediately rather than waiting for GC. */
public static void dispose (ByteBuffer buffer) {
if (!(buffer instanceof DirectBuffer)) return;
if (cleanerMethod != null) {
if (DirectBuffers.cleanerMethod != null) {
try {
cleanMethod.invoke(cleanerMethod.invoke(buffer));
DirectBuffers.cleanMethod.invoke(DirectBuffers.cleanerMethod.invoke(buffer));
} catch (Throwable ignored) {
}
}
Expand Down

0 comments on commit bb10a0b

Please sign in to comment.