|
|
|
@ -35,95 +35,96 @@ import java.lang.reflect.InvocationTargetException; |
|
|
|
|
import java.lang.reflect.Method; |
|
|
|
|
import java.nio.Buffer; |
|
|
|
|
import java.nio.ByteBuffer; |
|
|
|
|
import java.nio.DoubleBuffer; |
|
|
|
|
import java.util.logging.Level; |
|
|
|
|
import java.util.logging.Logger; |
|
|
|
|
|
|
|
|
|
/** |
|
|
|
|
* This class contains the reflection based way to remove DirectByteBuffers in java < 9, |
|
|
|
|
* allocation is done via ByteBuffer.allocateDirect |
|
|
|
|
* This class contains the reflection based way to remove DirectByteBuffers in |
|
|
|
|
* java < 9, allocation is done via ByteBuffer.allocateDirect |
|
|
|
|
*/ |
|
|
|
|
public final class ReflectionAllocator implements BufferAllocator { |
|
|
|
|
private static Method cleanerMethod = null; |
|
|
|
|
private static Method cleanMethod = null; |
|
|
|
|
private static Method viewedBufferMethod = null; |
|
|
|
|
private static Method freeMethod = null; |
|
|
|
|
private static Method cleanerMethod = null; |
|
|
|
|
private static Method cleanMethod = null; |
|
|
|
|
private static Method viewedBufferMethod = null; |
|
|
|
|
private static Method freeMethod = null; |
|
|
|
|
|
|
|
|
|
static { |
|
|
|
|
// Oracle JRE / OpenJDK
|
|
|
|
|
cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner"); |
|
|
|
|
cleanMethod = loadMethod("sun.misc.Cleaner", "clean"); |
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer"); |
|
|
|
|
if (viewedBufferMethod == null) { |
|
|
|
|
// They changed the name in Java 7 (???)
|
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment"); |
|
|
|
|
} |
|
|
|
|
static { |
|
|
|
|
// Oracle JRE / OpenJDK
|
|
|
|
|
cleanerMethod = loadMethod("sun.nio.ch.DirectBuffer", "cleaner"); |
|
|
|
|
cleanMethod = loadMethod("sun.misc.Cleaner", "clean"); |
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "viewedBuffer"); |
|
|
|
|
if (viewedBufferMethod == null) { |
|
|
|
|
// They changed the name in Java 7 (???)
|
|
|
|
|
viewedBufferMethod = loadMethod("sun.nio.ch.DirectBuffer", "attachment"); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// Apache Harmony (allocated directly, to not trigger allocator used logic in BufferUtils)
|
|
|
|
|
ByteBuffer bb = ByteBuffer.allocateDirect(1); |
|
|
|
|
Class<?> clazz = bb.getClass(); |
|
|
|
|
try { |
|
|
|
|
freeMethod = clazz.getMethod("free"); |
|
|
|
|
} catch (NoSuchMethodException ex) { |
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
// Apache Harmony (allocated directly, to not trigger allocator used
|
|
|
|
|
// logic in BufferUtils)
|
|
|
|
|
ByteBuffer bb = ByteBuffer.allocateDirect(1); |
|
|
|
|
Class<?> clazz = bb.getClass(); |
|
|
|
|
try { |
|
|
|
|
freeMethod = clazz.getMethod("free"); |
|
|
|
|
} catch (NoSuchMethodException ex) { |
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
private static Method loadMethod(String className, String methodName) { |
|
|
|
|
try { |
|
|
|
|
Method method = Class.forName(className).getMethod(methodName); |
|
|
|
|
method.setAccessible(true); |
|
|
|
|
return method; |
|
|
|
|
} catch (NoSuchMethodException ex) { |
|
|
|
|
return null; // the method was not found
|
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
return null; // setAccessible not allowed by security policy
|
|
|
|
|
} catch (ClassNotFoundException ex) { |
|
|
|
|
return null; // the direct buffer implementation was not found
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
private static Method loadMethod(String className, String methodName) { |
|
|
|
|
try { |
|
|
|
|
Method method = Class.forName(className).getMethod(methodName); |
|
|
|
|
method.setAccessible(true); |
|
|
|
|
return method; |
|
|
|
|
} catch (NoSuchMethodException ex) { |
|
|
|
|
return null; // the method was not found
|
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
return null; // setAccessible not allowed by security policy
|
|
|
|
|
} catch (ClassNotFoundException ex) { |
|
|
|
|
return null; // the direct buffer implementation was not found
|
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
/** |
|
|
|
|
* This function explicitly calls the Cleaner method of a direct buffer. |
|
|
|
|
* |
|
|
|
|
* @param toBeDestroyed |
|
|
|
|
* The direct buffer that will be "cleaned". Utilizes reflection. |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
public void destroyDirectBuffer(Buffer toBeDestroyed) { |
|
|
|
|
try { |
|
|
|
|
if (freeMethod != null) { |
|
|
|
|
freeMethod.invoke(toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
Object cleaner = cleanerMethod.invoke(toBeDestroyed); |
|
|
|
|
if (cleaner != null) { |
|
|
|
|
cleanMethod.invoke(cleaner); |
|
|
|
|
} else { |
|
|
|
|
// Try the alternate approach of getting the viewed buffer
|
|
|
|
|
// first
|
|
|
|
|
Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed); |
|
|
|
|
if (viewedBuffer != null) { |
|
|
|
|
destroyDirectBuffer((Buffer) viewedBuffer); |
|
|
|
|
} else { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "Buffer cannot be destroyed: {0}", toBeDestroyed); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (IllegalAccessException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (IllegalArgumentException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (InvocationTargetException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
@Override |
|
|
|
|
/** |
|
|
|
|
* This function explicitly calls the Cleaner method of a direct buffer. |
|
|
|
|
* |
|
|
|
|
* @param toBeDestroyed |
|
|
|
|
* The direct buffer that will be "cleaned". Utilizes reflection. |
|
|
|
|
* |
|
|
|
|
*/ |
|
|
|
|
public void destroyDirectBuffer(Buffer toBeDestroyed) { |
|
|
|
|
try { |
|
|
|
|
if (freeMethod != null) { |
|
|
|
|
freeMethod.invoke(toBeDestroyed); |
|
|
|
|
} else { |
|
|
|
|
Object cleaner = cleanerMethod.invoke(toBeDestroyed); |
|
|
|
|
if (cleaner != null) { |
|
|
|
|
cleanMethod.invoke(cleaner); |
|
|
|
|
} else { |
|
|
|
|
// Try the alternate approach of getting the viewed buffer
|
|
|
|
|
// first
|
|
|
|
|
Object viewedBuffer = viewedBufferMethod.invoke(toBeDestroyed); |
|
|
|
|
if (viewedBuffer != null) { |
|
|
|
|
destroyDirectBuffer((Buffer) viewedBuffer); |
|
|
|
|
} else { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, |
|
|
|
|
"Buffer cannot be destroyed: {0}", toBeDestroyed); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} catch (IllegalAccessException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (IllegalArgumentException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (InvocationTargetException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} catch (SecurityException ex) { |
|
|
|
|
Logger.getLogger(BufferUtils.class.getName()).log(Level.SEVERE, "{0}", ex); |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
@Override |
|
|
|
|
public ByteBuffer allocate(int size) { |
|
|
|
|
return ByteBuffer.allocateDirect(size); |
|
|
|
|
} |
|
|
|
|
@Override |
|
|
|
|
public ByteBuffer allocate(int size) { |
|
|
|
|
return ByteBuffer.allocateDirect(size); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
} |
|
|
|
|