forked from I2P_Developers/i2p.i2p
JRobin: Fix for Java 9 to remove dependency on Sun private classes
https://github.com/OpenNMS/jrobin/issues/3 http://stackoverflow.com/questions/1854398/how-to-garbage-collect-a-direct-buffer-java Code from http://sourceforge.net/p/tuer/code/HEAD/tree/pre_beta/src/main/java/engine/misc/DeallocationHelper.java unmodified, GPLv2
This commit is contained in:
770
apps/jrobin/java/src/engine/misc/DeallocationHelper.java
Normal file
770
apps/jrobin/java/src/engine/misc/DeallocationHelper.java
Normal file
@ -0,0 +1,770 @@
|
||||
/**
|
||||
* Copyright (c) 2006-2016 Julien Gouesse This program is free software; you can
|
||||
* redistribute it and/or modify it under the terms of the GNU General Public
|
||||
* License as published by the Free Software Foundation; either version 2 of the
|
||||
* License, or (at your option) any later version. This program is distributed
|
||||
* in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even
|
||||
* the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
* See the GNU General Public License for more details. You should have received
|
||||
* a copy of the GNU General Public License along with this program; if not,
|
||||
* write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
|
||||
* Boston, MA 02110-1301, USA.
|
||||
*/
|
||||
package engine.misc;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.Buffer;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.ByteOrder;
|
||||
import java.nio.CharBuffer;
|
||||
import java.nio.DoubleBuffer;
|
||||
import java.nio.FloatBuffer;
|
||||
import java.nio.IntBuffer;
|
||||
import java.nio.LongBuffer;
|
||||
import java.nio.ShortBuffer;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
/**
|
||||
* Helper to deallocate memory on the native heap allocated during the creation
|
||||
* of a direct byte buffer. It supports numerous virtual machines including
|
||||
* OpenJDK, Oracle/Sun Java, Android Dalvik Virtual Machine, Apache Harmony and
|
||||
* GNU Classpath. This class uses the syntax of Java 1.7 but it can work
|
||||
* correctly with Java 1.4 with a very few minor type changes when using the
|
||||
* maps and the collections. It relies on lots of implementation details but
|
||||
* it's robust enough to go on working (except when the implementors
|
||||
* intentionally use a very general class to store the buffers) despite minor
|
||||
* naming changes like those that occurred between Java 1.6 and Java 1.7. It
|
||||
* supports Java 1.9 despite the move of the cleaner from the package sun.misc
|
||||
* to jdk.internal.ref (in the module java.base). N.B: Releasing the native
|
||||
* memory of a sliced direct NIO buffer, the one of a direct NIO buffer created
|
||||
* with JNI or the one of any direct NIO buffer created by the virtual machine
|
||||
* or by a framework not under your control doesn't prevent the calls to methods
|
||||
* attempting to access such buffers. Those calls can throw an exception or
|
||||
* crash the virtual machine depending on the implementations.
|
||||
*
|
||||
* @author Julien Gouesse
|
||||
*/
|
||||
public class DeallocationHelper {
|
||||
|
||||
/**
|
||||
* tool responsible for releasing the native memory of a deallocatable byte
|
||||
* buffer
|
||||
*/
|
||||
public static abstract class Deallocator {
|
||||
|
||||
public Deallocator() {
|
||||
super();
|
||||
}
|
||||
|
||||
/**
|
||||
* releases the native memory of a deallocatable byte buffer
|
||||
*
|
||||
* @param directByteBuffer
|
||||
* deallocatable byte buffer
|
||||
*
|
||||
* @return <code>true</code> if the deallocation is successful,
|
||||
* otherwise <code>false</code>
|
||||
*/
|
||||
public abstract boolean run(final ByteBuffer directByteBuffer);
|
||||
}
|
||||
|
||||
public static class OracleSunOpenJdkDeallocator extends Deallocator {
|
||||
|
||||
private Method directByteBufferCleanerMethod;
|
||||
|
||||
private Method cleanerCleanMethod;
|
||||
|
||||
public OracleSunOpenJdkDeallocator() {
|
||||
super();
|
||||
try {
|
||||
final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer");
|
||||
directByteBufferCleanerMethod = directByteBufferClass.getDeclaredMethod("cleaner");
|
||||
/**
|
||||
* The return type is sun.misc.Cleaner in Java <= 1.8,
|
||||
* jdk.internal.ref.Cleaner in Java >= 1.9. Only the latter
|
||||
* implements the Runnable interface.
|
||||
*/
|
||||
final Class<?> cleanerClass = directByteBufferCleanerMethod.getReturnType();
|
||||
if (Runnable.class.isAssignableFrom(cleanerClass)) {
|
||||
cleanerCleanMethod = Runnable.class.getDeclaredMethod("run");
|
||||
} else {
|
||||
cleanerCleanMethod = cleanerClass.getDeclaredMethod("clean");
|
||||
}
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
logger.log(Level.WARNING,
|
||||
"The initialization of the deallocator for Oracle Java, Sun Java and OpenJDK has failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(final ByteBuffer directByteBuffer) {
|
||||
boolean success = false;
|
||||
if (directByteBufferCleanerMethod != null && cleanerCleanMethod != null) {
|
||||
final boolean directByteBufferCleanerMethodWasAccessible = directByteBufferCleanerMethod.isAccessible();
|
||||
final boolean cleanerCleanMethodWasAccessible = cleanerCleanMethod.isAccessible();
|
||||
try {
|
||||
// according to the Java documentation, by default, a reflected object is not accessible
|
||||
directByteBufferCleanerMethod.setAccessible(true);
|
||||
final Object cleaner = directByteBufferCleanerMethod.invoke(directByteBuffer);
|
||||
if (cleaner != null) {
|
||||
cleanerCleanMethod.setAccessible(true);
|
||||
cleanerCleanMethod.invoke(cleaner);
|
||||
success = true;
|
||||
}
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e);
|
||||
} finally {
|
||||
directByteBufferCleanerMethod.setAccessible(directByteBufferCleanerMethodWasAccessible);
|
||||
cleanerCleanMethod.setAccessible(cleanerCleanMethodWasAccessible);
|
||||
}
|
||||
}
|
||||
return (success);
|
||||
}
|
||||
}
|
||||
|
||||
public static class AndroidDeallocator extends Deallocator {
|
||||
|
||||
private Method directByteBufferFreeMethod;
|
||||
|
||||
public AndroidDeallocator() {
|
||||
super();
|
||||
try {
|
||||
final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer");
|
||||
directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free");
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
logger.log(Level.WARNING, "The initialization of the deallocator for Android has failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(final ByteBuffer directByteBuffer) {
|
||||
boolean success = false;
|
||||
if (directByteBufferFreeMethod != null) {
|
||||
final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible();
|
||||
try {
|
||||
directByteBufferFreeMethod.setAccessible(true);
|
||||
directByteBufferFreeMethod.invoke(directByteBuffer);
|
||||
success = true;
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e);
|
||||
} finally {
|
||||
directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible);
|
||||
}
|
||||
}
|
||||
return (success);
|
||||
}
|
||||
}
|
||||
|
||||
public static class GnuClasspathDeallocator extends Deallocator {
|
||||
|
||||
private Method vmDirectByteBufferFreeMethod;
|
||||
|
||||
private Field bufferAddressField;
|
||||
|
||||
public GnuClasspathDeallocator() {
|
||||
super();
|
||||
try {
|
||||
final Class<?> vmDirectByteBufferClass = Class.forName("java.nio.VMDirectByteBuffer");
|
||||
final Class<?> gnuClasspathPointerClass = Class.forName("gnu.classpath.Pointer");
|
||||
vmDirectByteBufferFreeMethod = vmDirectByteBufferClass.getDeclaredMethod("free",
|
||||
gnuClasspathPointerClass);
|
||||
bufferAddressField = Buffer.class.getDeclaredField("address");
|
||||
} catch (ClassNotFoundException | NoSuchMethodException | NoSuchFieldException e) {
|
||||
logger.log(Level.WARNING, "The initialization of the deallocator for GNU Classpath has failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(final ByteBuffer directByteBuffer) {
|
||||
boolean success = false;
|
||||
if (vmDirectByteBufferFreeMethod != null && bufferAddressField != null) {
|
||||
final boolean bufferAddressFieldWasAccessible = bufferAddressField.isAccessible();
|
||||
final boolean vmDirectByteBufferFreeMethodWasAccessible = vmDirectByteBufferFreeMethod.isAccessible();
|
||||
try {
|
||||
bufferAddressField.setAccessible(true);
|
||||
final Object address = bufferAddressField.get(directByteBuffer);
|
||||
if (address != null) {
|
||||
vmDirectByteBufferFreeMethod.setAccessible(true);
|
||||
vmDirectByteBufferFreeMethod.invoke(null, address);
|
||||
success = true;
|
||||
}
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e);
|
||||
} finally {
|
||||
bufferAddressField.setAccessible(bufferAddressFieldWasAccessible);
|
||||
vmDirectByteBufferFreeMethod.setAccessible(vmDirectByteBufferFreeMethodWasAccessible);
|
||||
}
|
||||
}
|
||||
return (success);
|
||||
}
|
||||
}
|
||||
|
||||
public static class ApacheHarmonyDeallocator extends Deallocator {
|
||||
|
||||
private Method directByteBufferFreeMethod;
|
||||
|
||||
public ApacheHarmonyDeallocator() {
|
||||
super();
|
||||
try {
|
||||
final Class<?> directByteBufferClass = Class.forName("java.nio.DirectByteBuffer");
|
||||
directByteBufferFreeMethod = directByteBufferClass.getDeclaredMethod("free");
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
logger.log(Level.WARNING, "The initialization of the deallocator for Apache Harmony has failed", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean run(final ByteBuffer directByteBuffer) {
|
||||
boolean success = false;
|
||||
if (directByteBufferFreeMethod != null) {
|
||||
final boolean directByteBufferFreeMethodWasAccessible = directByteBufferFreeMethod.isAccessible();
|
||||
try {
|
||||
directByteBufferFreeMethod.setAccessible(true);
|
||||
directByteBufferFreeMethod.invoke(directByteBuffer);
|
||||
success = true;
|
||||
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
logger.log(Level.WARNING, "The deallocation of a direct NIO buffer has failed", e);
|
||||
} finally {
|
||||
directByteBufferFreeMethod.setAccessible(directByteBufferFreeMethodWasAccessible);
|
||||
}
|
||||
}
|
||||
return (success);
|
||||
}
|
||||
}
|
||||
|
||||
private static final Logger logger = Logger.getLogger(DeallocationHelper.class.getName());
|
||||
|
||||
private Map<Class<?>, Field> attachmentOrByteBufferFieldMap;
|
||||
|
||||
private Set<Class<?>> deallocatableBufferClassSet;
|
||||
|
||||
private Deallocator deallocator;
|
||||
|
||||
/**
|
||||
* Default constructor
|
||||
*/
|
||||
public DeallocationHelper() {
|
||||
this(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Main constructor
|
||||
*
|
||||
* @param ignoreClassesAndFieldsHints
|
||||
* <code>true</code> if the known implementation details should
|
||||
* be ignored when looking for the classes and the fields used
|
||||
* for the native memory of the direct buffers (they are then
|
||||
* fully recomputed at runtime which is slower but safer),
|
||||
* otherwise <code>false</code>
|
||||
*/
|
||||
public DeallocationHelper(final boolean ignoreClassesAndFieldsHints) {
|
||||
super();
|
||||
final List<Buffer> buffersToDelete = new ArrayList<>();
|
||||
/**
|
||||
* builds the map used to determine the names of the fields containing
|
||||
* the direct byte buffers. The direct read only buffers and the sliced
|
||||
* buffers and the direct buffers for other primitive types than bytes
|
||||
* store their data into some direct byte buffers. Those direct byte
|
||||
* buffers often are the only one accessing directly to the native
|
||||
* memory. That's why it's necessary to find them when a developer
|
||||
* passes a direct NIO buffer. The code below relies on numerous
|
||||
* implementation details found in some classes not available in the
|
||||
* public APIs, it's used to find the fields faster in most of the
|
||||
* cases. The class names haven't changed since Java 1.4 unlike a few
|
||||
* field names.
|
||||
*/
|
||||
final Map<String, String> attachmentOrByteBufferFieldNameMap = new HashMap<>();
|
||||
final String javaVendor = System.getProperty("java.vendor");
|
||||
final String javaVersion = System.getProperty("java.version");
|
||||
if (!ignoreClassesAndFieldsHints) {
|
||||
if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")) {
|
||||
final String java14to16DirectBufferAttachmentFieldName = "viewedBuffer";
|
||||
final String java17to19DirectBufferAttachmentFieldName = "att";
|
||||
final String byteBufferAsNonByteBufferByteBufferFieldName = "bb";
|
||||
final String[] directBufferClassnames = new String[] { "java.nio.DirectByteBuffer",
|
||||
"java.nio.DirectByteBufferR", "java.nio.DirectCharBufferRS", "java.nio.DirectCharBufferRU",
|
||||
"java.nio.DirectCharBufferS", "java.nio.DirectCharBufferU", "java.nio.DirectDoubleBufferRS",
|
||||
"java.nio.DirectDoubleBufferRU", "java.nio.DirectDoubleBufferS", "java.nio.DirectDoubleBufferU",
|
||||
"java.nio.DirectFloatBufferRS", "java.nio.DirectFloatBufferRU", "java.nio.DirectFloatBufferS",
|
||||
"java.nio.DirectFloatBufferU", "java.nio.DirectIntBufferRS", "java.nio.DirectIntBufferRU",
|
||||
"java.nio.DirectIntBufferS", "java.nio.DirectIntBufferU", "java.nio.DirectLongBufferRS",
|
||||
"java.nio.DirectLongBufferRU", "java.nio.DirectLongBufferS", "java.nio.DirectLongBufferU",
|
||||
"java.nio.DirectShortBufferRS", "java.nio.DirectShortBufferRU", "java.nio.DirectShortBufferS",
|
||||
"java.nio.DirectShortBufferU" };
|
||||
final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBufferB",
|
||||
"java.nio.ByteBufferAsCharBufferL", "java.nio.ByteBufferAsCharBufferRB",
|
||||
"java.nio.ByteBufferAsCharBufferRL", "java.nio.ByteBufferAsDoubleBufferB",
|
||||
"java.nio.ByteBufferAsDoubleBufferL", "java.nio.ByteBufferAsDoubleBufferRB",
|
||||
"java.nio.ByteBufferAsDoubleBufferRL", "java.nio.ByteBufferAsFloatBufferB",
|
||||
"java.nio.ByteBufferAsFloatBufferL", "java.nio.ByteBufferAsFloatBufferRB",
|
||||
"java.nio.ByteBufferAsFloatBufferRL", "java.nio.ByteBufferAsIntBufferB",
|
||||
"java.nio.ByteBufferAsIntBufferL", "java.nio.ByteBufferAsIntBufferRB",
|
||||
"java.nio.ByteBufferAsIntBufferRL", "java.nio.ByteBufferAsLongBufferB",
|
||||
"java.nio.ByteBufferAsLongBufferL", "java.nio.ByteBufferAsLongBufferRB",
|
||||
"java.nio.ByteBufferAsLongBufferRL", "java.nio.ByteBufferAsShortBufferB",
|
||||
"java.nio.ByteBufferAsShortBufferL", "java.nio.ByteBufferAsShortBufferRB",
|
||||
"java.nio.ByteBufferAsShortBufferRL" };
|
||||
final String[] javaVersionElements = System.getProperty("java.version").split("\\.");
|
||||
final int indexOfEarlyAccessSuffix = javaVersionElements[0].lastIndexOf("-ea");
|
||||
if (indexOfEarlyAccessSuffix != -1) {
|
||||
// drops the "-ea" suffix from the major version number for
|
||||
// an early access build
|
||||
javaVersionElements[0] = javaVersionElements[0].substring(0, indexOfEarlyAccessSuffix);
|
||||
}
|
||||
final int major, minor;
|
||||
if (javaVersionElements.length >= 2) {
|
||||
major = Integer.parseInt(javaVersionElements[0]);
|
||||
minor = Integer.parseInt(javaVersionElements[1]);
|
||||
} else {
|
||||
major = 1;
|
||||
minor = Integer.parseInt(javaVersionElements[0]);
|
||||
}
|
||||
final String directBufferAttachmentFieldName;
|
||||
if (minor == 1 && major <= 6)
|
||||
directBufferAttachmentFieldName = java14to16DirectBufferAttachmentFieldName;
|
||||
else
|
||||
directBufferAttachmentFieldName = java17to19DirectBufferAttachmentFieldName;
|
||||
for (final String directBufferClassname : directBufferClassnames)
|
||||
attachmentOrByteBufferFieldNameMap.put(directBufferClassname, directBufferAttachmentFieldName);
|
||||
for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames)
|
||||
attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname,
|
||||
byteBufferAsNonByteBufferByteBufferFieldName);
|
||||
} else if (javaVendor.equals("The Android Project")) {
|
||||
final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer";
|
||||
final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.ByteBufferAsCharBuffer",
|
||||
"java.nio.ByteBufferAsDoubleBuffer", "java.nio.ByteBufferAsFloatBuffer",
|
||||
"java.nio.ByteBufferAsIntBuffer", "java.nio.ByteBufferAsLongBuffer",
|
||||
"java.nio.ByteBufferAsShortBuffer" };
|
||||
for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames)
|
||||
attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname,
|
||||
byteBufferAsNonByteBufferByteBufferFieldName);
|
||||
} else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) {
|
||||
final String byteBufferAsNonByteBufferByteBufferFieldName = "bb";
|
||||
final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharViewBufferImpl",
|
||||
"java.nio.DoubleViewBufferImpl", "java.nio.FloatViewBufferImpl", "java.nio.IntViewBufferImpl",
|
||||
"java.nio.LongViewBufferImpl", "java.nio.ShortViewBufferImpl" };
|
||||
for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames)
|
||||
attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname,
|
||||
byteBufferAsNonByteBufferByteBufferFieldName);
|
||||
} else if (javaVendor.contains("Apache")) {
|
||||
final String byteBufferAsNonByteBufferByteBufferFieldName = "byteBuffer";
|
||||
final String[] byteBufferAsNonByteBufferClassnames = new String[] { "java.nio.CharToByteBufferAdapter",
|
||||
"java.nio.DoubleToByteBufferAdapter", "java.nio.FloatToByteBufferAdapter",
|
||||
"java.nio.IntToByteBufferAdapter", "java.nio.LongToByteBufferAdapter",
|
||||
"java.nio.ShortToByteBufferAdapter" };
|
||||
for (final String byteBufferAsNonByteBufferClassname : byteBufferAsNonByteBufferClassnames)
|
||||
attachmentOrByteBufferFieldNameMap.put(byteBufferAsNonByteBufferClassname,
|
||||
byteBufferAsNonByteBufferByteBufferFieldName);
|
||||
} else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM
|
||||
} else if (javaVendor.contains("IBM")) {// TODO J9
|
||||
}
|
||||
}
|
||||
// checks if these classes are in the class library
|
||||
if (!attachmentOrByteBufferFieldNameMap.isEmpty()) {
|
||||
final List<String> classnamesToRemove = new ArrayList<>();
|
||||
for (final String classname : attachmentOrByteBufferFieldNameMap.keySet())
|
||||
try {
|
||||
Class.forName(classname);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
classnamesToRemove.add(classname);
|
||||
}
|
||||
for (final String classnameToRemove : classnamesToRemove)
|
||||
attachmentOrByteBufferFieldNameMap.remove(classnameToRemove);
|
||||
}
|
||||
// builds the map used to determine the fields containing the direct
|
||||
// byte buffers
|
||||
attachmentOrByteBufferFieldMap = new HashMap<>();
|
||||
if (!attachmentOrByteBufferFieldNameMap.isEmpty())
|
||||
for (final Entry<String, String> attachmentOrByteBufferFieldNameEntry : attachmentOrByteBufferFieldNameMap
|
||||
.entrySet()) {
|
||||
final String classname = attachmentOrByteBufferFieldNameEntry.getKey();
|
||||
final String fieldname = attachmentOrByteBufferFieldNameEntry.getValue();
|
||||
try {
|
||||
final Class<?> bufferClass = Class.forName(classname);
|
||||
Field bufferField = null;
|
||||
Class<?> bufferIntermediaryClass = bufferClass;
|
||||
final List<Class<?>> intermediaryClassWithoutBufferList = new ArrayList<>();
|
||||
while (bufferIntermediaryClass != null) {
|
||||
try {
|
||||
bufferField = bufferIntermediaryClass.getDeclaredField(fieldname);
|
||||
} catch (NoSuchFieldException nsfe) {
|
||||
if (!bufferIntermediaryClass.equals(Object.class)
|
||||
&& !bufferIntermediaryClass.equals(Buffer.class))
|
||||
intermediaryClassWithoutBufferList.add(bufferIntermediaryClass);
|
||||
}
|
||||
bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass();
|
||||
}
|
||||
if (bufferField == null) {
|
||||
final String superClassesMsg;
|
||||
if (intermediaryClassWithoutBufferList.isEmpty())
|
||||
superClassesMsg = "";
|
||||
else if (intermediaryClassWithoutBufferList.size() == 1)
|
||||
superClassesMsg = " and in its super class "
|
||||
+ intermediaryClassWithoutBufferList.get(0).getName();
|
||||
else {
|
||||
final StringBuilder builder = new StringBuilder();
|
||||
builder.append(" and in its super classes");
|
||||
int classIndex = 0;
|
||||
for (final Class<?> intermediaryClassWithoutBuffer : intermediaryClassWithoutBufferList) {
|
||||
builder.append(' ');
|
||||
builder.append(intermediaryClassWithoutBuffer.getName());
|
||||
if (classIndex < intermediaryClassWithoutBufferList.size() - 1)
|
||||
builder.append(',');
|
||||
classIndex++;
|
||||
}
|
||||
superClassesMsg = builder.toString();
|
||||
}
|
||||
logger.warning("The field " + fieldname + " hasn't been found in the class " + classname
|
||||
+ superClassesMsg);
|
||||
} else {// the field has been found, stores it into the map
|
||||
attachmentOrByteBufferFieldMap.put(bufferClass, bufferField);
|
||||
}
|
||||
} catch (ClassNotFoundException cnfe) {// TODO The Java version
|
||||
// isn't very useful
|
||||
// under
|
||||
// Android as it is
|
||||
// always zero, rather
|
||||
// use
|
||||
// android.os.Build.VERSION.RELEASE
|
||||
// to show something
|
||||
// meaningful supported
|
||||
// since the API level 1
|
||||
final String msg = "The class " + classname
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
}
|
||||
// if a known implementation has drastically changed or if the current
|
||||
// implementation is unknown
|
||||
if (attachmentOrByteBufferFieldNameMap.isEmpty()) {// detects everything
|
||||
// with the
|
||||
// reflection API
|
||||
// creates all
|
||||
// possible kinds of
|
||||
// direct NIO buffer
|
||||
// that can contain
|
||||
// buffers (sliced
|
||||
// buffers and views)
|
||||
final ByteBuffer slicedBigEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2)
|
||||
.order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice()
|
||||
.asReadOnlyBuffer();
|
||||
final ByteBuffer slicedBigEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2)
|
||||
.order(ByteOrder.BIG_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice();
|
||||
final CharBuffer bigEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asCharBuffer();
|
||||
final CharBuffer bigEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asCharBuffer();
|
||||
final DoubleBuffer bigEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asDoubleBuffer();
|
||||
final DoubleBuffer bigEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asDoubleBuffer();
|
||||
final FloatBuffer bigEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asFloatBuffer();
|
||||
final FloatBuffer bigEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asFloatBuffer();
|
||||
final IntBuffer bigEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN)
|
||||
.asReadOnlyBuffer().asIntBuffer();
|
||||
final IntBuffer bigEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1).order(ByteOrder.BIG_ENDIAN)
|
||||
.asIntBuffer();
|
||||
final LongBuffer bigEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asLongBuffer();
|
||||
final LongBuffer bigEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asLongBuffer();
|
||||
final ShortBuffer bigEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asReadOnlyBuffer().asShortBuffer();
|
||||
final ShortBuffer bigEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.BIG_ENDIAN).asShortBuffer();
|
||||
final ByteBuffer slicedLittleEndianReadOnlyDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice()
|
||||
.asReadOnlyBuffer();
|
||||
final ByteBuffer slicedLittleEndianReadWriteDirectByteBuffer = ((ByteBuffer) ByteBuffer.allocateDirect(2)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).put((byte) 0).put((byte) 0).position(1).limit(2)).slice();
|
||||
final CharBuffer littleEndianReadOnlyDirectCharBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asCharBuffer();
|
||||
final CharBuffer littleEndianReadWriteDirectCharBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asCharBuffer();
|
||||
final DoubleBuffer littleEndianReadOnlyDirectDoubleBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asDoubleBuffer();
|
||||
final DoubleBuffer littleEndianReadWriteDirectDoubleBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asDoubleBuffer();
|
||||
final FloatBuffer littleEndianReadOnlyDirectFloatBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asFloatBuffer();
|
||||
final FloatBuffer littleEndianReadWriteDirectFloatBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asFloatBuffer();
|
||||
final IntBuffer littleEndianReadOnlyDirectIntBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asIntBuffer();
|
||||
final IntBuffer littleEndianReadWriteDirectIntBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asIntBuffer();
|
||||
final LongBuffer littleEndianReadOnlyDirectLongBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asLongBuffer();
|
||||
final LongBuffer littleEndianReadWriteDirectLongBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asLongBuffer();
|
||||
final ShortBuffer littleEndianReadOnlyDirectShortBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asReadOnlyBuffer().asShortBuffer();
|
||||
final ShortBuffer littleEndianReadWriteDirectShortBuffer = ByteBuffer.allocateDirect(1)
|
||||
.order(ByteOrder.LITTLE_ENDIAN).asShortBuffer();
|
||||
final List<Buffer> buffers = new ArrayList<>();
|
||||
buffers.add(slicedBigEndianReadOnlyDirectByteBuffer);
|
||||
buffers.add(slicedBigEndianReadWriteDirectByteBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectCharBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectCharBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectDoubleBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectDoubleBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectFloatBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectFloatBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectIntBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectIntBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectLongBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectLongBuffer);
|
||||
buffers.add(bigEndianReadOnlyDirectShortBuffer);
|
||||
buffers.add(bigEndianReadWriteDirectShortBuffer);
|
||||
buffers.add(slicedLittleEndianReadOnlyDirectByteBuffer);
|
||||
buffers.add(slicedLittleEndianReadWriteDirectByteBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectCharBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectCharBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectDoubleBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectDoubleBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectFloatBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectFloatBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectIntBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectIntBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectLongBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectLongBuffer);
|
||||
buffers.add(littleEndianReadOnlyDirectShortBuffer);
|
||||
buffers.add(littleEndianReadWriteDirectShortBuffer);
|
||||
// gets the fields to access the contained buffers
|
||||
for (Buffer buffer : buffers) {
|
||||
final Class<?> bufferClass = buffer.getClass();
|
||||
if (!attachmentOrByteBufferFieldMap.containsKey(bufferClass)) {
|
||||
Field bufferField = null;
|
||||
Class<?> bufferIntermediaryClass = bufferClass;
|
||||
while (bufferIntermediaryClass != null && bufferField == null) {
|
||||
for (final Field field : bufferIntermediaryClass.getDeclaredFields()) {
|
||||
final boolean fieldWasAccessible = field.isAccessible();
|
||||
try {
|
||||
field.setAccessible(true);
|
||||
final Object fieldValue = field.get(buffer);
|
||||
if (fieldValue != null && fieldValue instanceof Buffer) {
|
||||
bufferField = field;
|
||||
break;
|
||||
}
|
||||
} catch (IllegalAccessException iae) {
|
||||
logger.log(Level.WARNING, "Cannot access the field " + field.getName()
|
||||
+ " of the class " + bufferIntermediaryClass.getName(), iae);
|
||||
} finally {
|
||||
field.setAccessible(fieldWasAccessible);
|
||||
}
|
||||
}
|
||||
bufferIntermediaryClass = bufferIntermediaryClass.getSuperclass();
|
||||
}
|
||||
if (bufferField != null)
|
||||
attachmentOrByteBufferFieldMap.put(bufferClass, bufferField);
|
||||
}
|
||||
}
|
||||
// cleans the mess
|
||||
buffersToDelete.addAll(buffers);
|
||||
}
|
||||
// builds the set of classes whose instances can be deallocated
|
||||
deallocatableBufferClassSet = new HashSet<>();
|
||||
if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation")
|
||||
|| javaVendor.equals("The Android Project")) {
|
||||
Class<?> directByteBufferClass = null;
|
||||
final String directByteBufferClassName = "java.nio.DirectByteBuffer";
|
||||
try {
|
||||
directByteBufferClass = Class.forName(directByteBufferClassName);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
final String msg = "The class " + directByteBufferClassName
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
if (directByteBufferClass != null)
|
||||
deallocatableBufferClassSet.add(directByteBufferClass);
|
||||
} else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc.")) {
|
||||
Class<?> readOnlyDirectByteBufferClass = null;
|
||||
final String readOnlyDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadOnly";
|
||||
try {
|
||||
readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
final String msg = "The class " + readOnlyDirectByteBufferClassName
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
if (readOnlyDirectByteBufferClass != null)
|
||||
deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass);
|
||||
Class<?> readWriteDirectByteBufferClass = null;
|
||||
final String readWriteDirectByteBufferClassName = "java.nio.DirectByteBufferImpl.ReadWrite";
|
||||
try {
|
||||
readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
final String msg = "The class " + readWriteDirectByteBufferClassName
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
if (readWriteDirectByteBufferClass != null)
|
||||
deallocatableBufferClassSet.add(readWriteDirectByteBufferClass);
|
||||
} else if (javaVendor.contains("Apache")) {
|
||||
Class<?> readOnlyDirectByteBufferClass = null;
|
||||
final String readOnlyDirectByteBufferClassName = "java.nio.ReadOnlyDirectByteBuffer";
|
||||
try {
|
||||
readOnlyDirectByteBufferClass = Class.forName(readOnlyDirectByteBufferClassName);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
final String msg = "The class " + readOnlyDirectByteBufferClassName
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
if (readOnlyDirectByteBufferClass != null)
|
||||
deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass);
|
||||
Class<?> readWriteDirectByteBufferClass = null;
|
||||
final String readWriteDirectByteBufferClassName = "java.nio.ReadWriteDirectByteBuffer";
|
||||
try {
|
||||
readWriteDirectByteBufferClass = Class.forName(readWriteDirectByteBufferClassName);
|
||||
} catch (ClassNotFoundException cnfe) {
|
||||
final String msg = "The class " + readWriteDirectByteBufferClassName
|
||||
+ " hasn't been found while initializing the deallocator. Java vendor: " + javaVendor
|
||||
+ " Java version: " + javaVersion;
|
||||
logger.log(Level.WARNING, msg, cnfe);
|
||||
}
|
||||
if (readWriteDirectByteBufferClass != null)
|
||||
deallocatableBufferClassSet.add(readWriteDirectByteBufferClass);
|
||||
} else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM
|
||||
} else if (javaVendor.contains("IBM")) {// TODO J9
|
||||
}
|
||||
// if there is no known implementation class of the direct byte buffers
|
||||
if (deallocatableBufferClassSet.isEmpty()) {// creates a read write
|
||||
// direct byte buffer
|
||||
final ByteBuffer dummyReadWriteDirectByteBuffer = ByteBuffer.allocateDirect(1);
|
||||
// gets its class
|
||||
final Class<?> readWriteDirectByteBufferClass = dummyReadWriteDirectByteBuffer.getClass();
|
||||
// stores this class
|
||||
deallocatableBufferClassSet.add(readWriteDirectByteBufferClass);
|
||||
// cleans the mess
|
||||
buffersToDelete.add(dummyReadWriteDirectByteBuffer);
|
||||
// creates a read only direct byte buffer
|
||||
final ByteBuffer dummyReadOnlyDirectByteBuffer = ByteBuffer.allocateDirect(1).asReadOnlyBuffer();
|
||||
// gets its class
|
||||
final Class<?> readOnlyDirectByteBufferClass = dummyReadOnlyDirectByteBuffer.getClass();
|
||||
// stores this class
|
||||
deallocatableBufferClassSet.add(readOnlyDirectByteBufferClass);
|
||||
// cleans the mess
|
||||
buffersToDelete.add(dummyReadOnlyDirectByteBuffer);
|
||||
}
|
||||
// builds the deallocator responsible for releasing the native memory of
|
||||
// a deallocatable byte buffer
|
||||
if (javaVendor.equals("Sun Microsystems Inc.") || javaVendor.equals("Oracle Corporation"))
|
||||
deallocator = new OracleSunOpenJdkDeallocator();
|
||||
else if (javaVendor.equals("The Android Project"))
|
||||
deallocator = new AndroidDeallocator();
|
||||
else if (/* javaVendor.equals("Apple Inc.")|| */javaVendor.equals("Free Software Foundation, Inc."))
|
||||
deallocator = new GnuClasspathDeallocator();
|
||||
else if (javaVendor.contains("Apache"))
|
||||
deallocator = new ApacheHarmonyDeallocator();
|
||||
else if (javaVendor.equals("Jeroen Frijters")) {// TODO IKVM
|
||||
deallocator = null;
|
||||
} else if (javaVendor.contains("IBM")) {// TODO J9
|
||||
deallocator = null;
|
||||
} else
|
||||
deallocator = null;
|
||||
// final cleanup
|
||||
for (final Buffer bufferToDelete : buffersToDelete)
|
||||
deallocate(bufferToDelete);
|
||||
}
|
||||
|
||||
public ByteBuffer findDeallocatableBuffer(Buffer buffer) {
|
||||
final ByteBuffer deallocatableDirectByteBuffer;
|
||||
// looks only for the direct buffers
|
||||
if (buffer != null && buffer.isDirect()) {// looks for any contained
|
||||
// buffer in the passed buffer
|
||||
final Class<?> bufferClass = buffer.getClass();
|
||||
final Field attachmentOrByteBufferField = attachmentOrByteBufferFieldMap == null ? null
|
||||
: attachmentOrByteBufferFieldMap.get(bufferClass);
|
||||
final Buffer attachmentBufferOrByteBuffer;
|
||||
if (attachmentOrByteBufferField == null)
|
||||
attachmentBufferOrByteBuffer = null;
|
||||
else {
|
||||
Object attachedObjectOrByteBuffer;
|
||||
final boolean attachedObjectOrByteBufferFieldWasAccessible = attachmentOrByteBufferField.isAccessible();
|
||||
try {
|
||||
attachmentOrByteBufferField.setAccessible(true);
|
||||
attachedObjectOrByteBuffer = attachmentOrByteBufferField.get(buffer);
|
||||
} catch (IllegalArgumentException | IllegalAccessException iae) {
|
||||
attachedObjectOrByteBuffer = null;
|
||||
} finally {
|
||||
attachmentOrByteBufferField.setAccessible(attachedObjectOrByteBufferFieldWasAccessible);
|
||||
}
|
||||
if (attachedObjectOrByteBuffer instanceof Buffer)
|
||||
attachmentBufferOrByteBuffer = (Buffer) attachedObjectOrByteBuffer;
|
||||
else
|
||||
attachmentBufferOrByteBuffer = null;
|
||||
}
|
||||
// if there is no buffer inside the buffer given in input
|
||||
if (attachmentBufferOrByteBuffer == null) {// if it's a direct byte
|
||||
// buffer and if it's an
|
||||
// instance of
|
||||
// a deallocatable buffer
|
||||
// class
|
||||
if (buffer instanceof ByteBuffer && deallocatableBufferClassSet.contains(bufferClass))
|
||||
deallocatableDirectByteBuffer = (ByteBuffer) buffer;
|
||||
else {// it's not a byte buffer or it's not a
|
||||
// deallocatable buffer
|
||||
deallocatableDirectByteBuffer = null;
|
||||
final String bufferClassName = bufferClass.getName();
|
||||
logger.warning("No deallocatable buffer has been found for an instance of the class "
|
||||
+ bufferClassName + " whereas it is a direct NIO buffer");
|
||||
}
|
||||
} else {// the passed buffer contains another buffer, looks for a
|
||||
// deallocatable buffer inside it
|
||||
deallocatableDirectByteBuffer = findDeallocatableBuffer(attachmentBufferOrByteBuffer);
|
||||
}
|
||||
} else {// there is no need to clean the heap based buffers
|
||||
deallocatableDirectByteBuffer = null;
|
||||
}
|
||||
return deallocatableDirectByteBuffer;
|
||||
}
|
||||
|
||||
public void deallocate(final Buffer buffer) {
|
||||
if (deallocator != null) {
|
||||
final ByteBuffer deallocatableBuffer = findDeallocatableBuffer(buffer);
|
||||
if (deallocatableBuffer != null)
|
||||
deallocator.run(deallocatableBuffer);
|
||||
}
|
||||
}
|
||||
|
||||
public Deallocator getDeallocator() {
|
||||
return (deallocator);
|
||||
}
|
||||
|
||||
public void setDeallocator(Deallocator deallocator) {
|
||||
this.deallocator = deallocator;
|
||||
}
|
||||
|
||||
public Map<Class<?>, Field> getAttachmentOrByteBufferFieldMap() {
|
||||
return (attachmentOrByteBufferFieldMap);
|
||||
}
|
||||
|
||||
public void setAttachmentOrByteBufferFieldMap(Map<Class<?>, Field> attachmentOrByteBufferFieldMap) {
|
||||
this.attachmentOrByteBufferFieldMap = attachmentOrByteBufferFieldMap;
|
||||
}
|
||||
|
||||
public Set<Class<?>> getDeallocatableBufferClassSet() {
|
||||
return (deallocatableBufferClassSet);
|
||||
}
|
||||
|
||||
public void setDeallocatableBufferClassSet(Set<Class<?>> deallocatableBufferClassSet) {
|
||||
this.deallocatableBufferClassSet = deallocatableBufferClassSet;
|
||||
}
|
||||
}
|
@ -24,7 +24,7 @@ import java.nio.MappedByteBuffer;
|
||||
import java.nio.channels.FileChannel;
|
||||
|
||||
|
||||
import sun.nio.ch.DirectBuffer;
|
||||
import engine.misc.DeallocationHelper;
|
||||
|
||||
/**
|
||||
* JRobin backend which is used to store RRD data to ordinary disk files by
|
||||
@ -35,6 +35,7 @@ import sun.nio.ch.DirectBuffer;
|
||||
public class RrdNioBackend extends RrdFileBackend {
|
||||
private final SyncManager m_syncManager;
|
||||
private MappedByteBuffer m_byteBuffer = null;
|
||||
private static final DeallocationHelper _dHelper = new DeallocationHelper();
|
||||
|
||||
/**
|
||||
* Creates RrdFileBackend object for the given file path, backed by
|
||||
@ -105,9 +106,7 @@ public class RrdNioBackend extends RrdFileBackend {
|
||||
stopSchedule();
|
||||
}
|
||||
if (m_byteBuffer != null) {
|
||||
if (m_byteBuffer instanceof DirectBuffer) {
|
||||
((DirectBuffer) m_byteBuffer).cleaner().clean();
|
||||
}
|
||||
_dHelper.deallocate(m_byteBuffer);
|
||||
m_byteBuffer = null;
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user