|
|
|
@ -40,7 +40,7 @@ import java.util.logging.Logger; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This class contains the reflection based way to remove DirectByteBuffers in |
|
|
|
|
* java < 9, allocation is done via ByteBuffer.allocateDirect |
|
|
|
|
* java, allocation is done via ByteBuffer.allocateDirect |
|
|
|
|
*/ |
|
|
|
|
public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
private static Method cleanerMethod = null; |
|
|
|
@ -54,7 +54,7 @@ public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
cleanMethod = loadMethod("sun.misc.Cleaner", "clean"); |
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer"); |
|
|
|
|
if (viewedBufferMethod == null) { |
|
|
|
|
// They changed the name in Java 7 (???)
|
|
|
|
|
// They changed the name in Java 7
|
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -72,7 +72,7 @@ public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
private static Method loadMethod(String className, String methodName) { |
|
|
|
|
try { |
|
|
|
|
Method method = Class.forName(className).getMethod(methodName); |
|
|
|
|
method.setAccessible(true); |
|
|
|
|
method.setAccessible(true);// according to the Java documentation, by default, a reflected object is not accessible
|
|
|
|
|
return method; |
|
|
|
|
} catch (NoSuchMethodException ex) { |
|
|
|
|
return null; // the method was not found
|
|
|
|
@ -80,6 +80,12 @@ public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
return null; // setAccessible not allowed by security policy
|
|
|
|
|
} catch (ClassNotFoundException ex) { |
|
|
|
|
return null; // the direct buffer implementation was not found
|
|
|
|
|
} catch (Throwable t) { |
|
|
|
|
if (t.getClass().getName().equals("java.lang.reflect.InaccessibleObjectException")) { |
|
|
|
|
return null;// the class is in an exported module
|
|
|
|
|
} else { |
|
|
|
|
throw t; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
@ -96,13 +102,52 @@ public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
if (freeMethod != null) { |
|
|
|
|
freeMethod.invoke(toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
Object cleaner = cleanerMethod.invoke(toBeDestroyed); |
|
|
|
|
//TODO load the methods only once, store them into a cache (only for Java >= 9)
|
|
|
|
|
Method localCleanerMethod; |
|
|
|
|
if (cleanerMethod == null) { |
|
|
|
|
localCleanerMethod = loadMethod(toBeDestroyed.getClass().getName(), "cleaner"); |
|
|
|
|
} else { |
|
|
|
|
localCleanerMethod = cleanerMethod; |
|
|
|
|
} |
|
|
|
|
if (localCleanerMethod == null) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, |
|
|
|
|
"Buffer cannot be destroyed: {0}", toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
Object cleaner = localCleanerMethod.invoke(toBeDestroyed); |
|
|
|
|
if (cleaner != null) { |
|
|
|
|
cleanMethod.invoke(cleaner); |
|
|
|
|
Method localCleanMethod; |
|
|
|
|
if (cleanMethod == null) { |
|
|
|
|
if (cleaner instanceof Runnable) { |
|
|
|
|
// jdk.internal.ref.Cleaner implements Runnable in Java 9
|
|
|
|
|
localCleanMethod = loadMethod(Runnable.class.getName(), "run"); |
|
|
|
|
} else { |
|
|
|
|
// sun.misc.Cleaner does not implement Runnable in Java < 9
|
|
|
|
|
localCleanMethod = loadMethod(cleaner.getClass().getName(), "clean"); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
// Try the alternate approach of getting the viewed buffer
|
|
|
|
|
localCleanMethod = cleanMethod; |
|
|
|
|
} |
|
|
|
|
if (localCleanMethod == null) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, |
|
|
|
|
"Buffer cannot be destroyed: {0}", toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
localCleanMethod.invoke(cleaner); |
|
|
|
|
} |
|
|
|
|
} else { |
|
|
|
|
Method localViewedBufferMethod; |
|
|
|
|
if (viewedBufferMethod == null) { |
|
|
|
|
localViewedBufferMethod = loadMethod(toBeDestroyed.getClass().getName(), "viewedBuffer"); |
|
|
|
|
} else { |
|
|
|
|
localViewedBufferMethod = viewedBufferMethod; |
|
|
|
|
} |
|
|
|
|
if (localViewedBufferMethod == null) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, |
|
|
|
|
"Buffer cannot be destroyed: {0}", toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
// Try the alternate approach of getting the viewed
|
|
|
|
|
// buffer
|
|
|
|
|
// first
|
|
|
|
|
Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed); |
|
|
|
|
Object viewedBuffer = localViewedBufferMethod.invoke(toBeDestroyed); |
|
|
|
|
if (viewedBuffer != null) { |
|
|
|
|
destroyDirectBuffer((Buffer) viewedBuffer); |
|
|
|
|
} else { |
|
|
|
@ -111,6 +156,8 @@ public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (IllegalAccessException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (IllegalArgumentException ex) { |
|
|
|
|