Fix and simplify freeing a direct buffer / Fix Android support
Motivation:
6e8ba291cf
introduced a regression in Android because Android does not have sun.nio.ch.DirectBuffer (see #2330.) I also found PlatformDependent0.freeDirectBuffer() and freeDirectBufferUnsafe() are pretty much same after the commit and the unsafe version should be removed.
Modifications:
- Do not use the pooled allocator in Android because it's too resource hungry for Androids.
- Merge PlatformDependent0.freeDirectBuffer() and freeDirectBufferUnsafe() into one method.
- Make the Unsafe unavailable when sun.nio.ch.DirectBuffer is unavailable. We could keep the Unsafe available and handle the sun.nio.ch.DirectBuffer case separately, but I don't want to complicate our code just because of that. All supported JDK versions have sun.nio.ch.DirectBuffer if the Unsafe is available.
Result:
Simpler code. Fixes Android support (#2330)
This commit is contained in:
parent
79541bceb6
commit
ab72dd7303
@ -16,6 +16,7 @@
|
|||||||
package io.netty.buffer;
|
package io.netty.buffer;
|
||||||
|
|
||||||
import io.netty.util.CharsetUtil;
|
import io.netty.util.CharsetUtil;
|
||||||
|
import io.netty.util.internal.PlatformDependent;
|
||||||
import io.netty.util.internal.SystemPropertyUtil;
|
import io.netty.util.internal.SystemPropertyUtil;
|
||||||
import io.netty.util.internal.logging.InternalLogger;
|
import io.netty.util.internal.logging.InternalLogger;
|
||||||
import io.netty.util.internal.logging.InternalLoggerFactory;
|
import io.netty.util.internal.logging.InternalLoggerFactory;
|
||||||
@ -48,7 +49,10 @@ public final class ByteBufUtil {
|
|||||||
HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F];
|
HEXDUMP_TABLE[(i << 1) + 1] = DIGITS[i & 0x0F];
|
||||||
}
|
}
|
||||||
|
|
||||||
String allocType = SystemPropertyUtil.get("io.netty.allocator.type", "pooled").toLowerCase(Locale.US).trim();
|
String allocType = SystemPropertyUtil.get(
|
||||||
|
"io.netty.allocator.type", PlatformDependent.isAndroid() ? "unpooled" : "pooled");
|
||||||
|
allocType = allocType.toLowerCase(Locale.US).trim();
|
||||||
|
|
||||||
ByteBufAllocator alloc;
|
ByteBufAllocator alloc;
|
||||||
if ("unpooled".equals(allocType)) {
|
if ("unpooled".equals(allocType)) {
|
||||||
alloc = UnpooledByteBufAllocator.DEFAULT;
|
alloc = UnpooledByteBufAllocator.DEFAULT;
|
||||||
|
@ -251,12 +251,8 @@ public final class PlatformDependent {
|
|||||||
* the current platform does not support this operation or the specified buffer is not a direct buffer.
|
* the current platform does not support this operation or the specified buffer is not a direct buffer.
|
||||||
*/
|
*/
|
||||||
public static void freeDirectBuffer(ByteBuffer buffer) {
|
public static void freeDirectBuffer(ByteBuffer buffer) {
|
||||||
if (buffer.isDirect()) {
|
if (hasUnsafe()) {
|
||||||
if (hasUnsafe()) {
|
PlatformDependent0.freeDirectBuffer(buffer);
|
||||||
PlatformDependent0.freeDirectBufferUnsafe(buffer);
|
|
||||||
} else {
|
|
||||||
PlatformDependent0.freeDirectBuffer(buffer);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,39 +48,40 @@ final class PlatformDependent0 {
|
|||||||
private static final boolean UNALIGNED;
|
private static final boolean UNALIGNED;
|
||||||
|
|
||||||
static {
|
static {
|
||||||
ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
boolean directBufferFreeable = false;
|
||||||
Field cleanerField;
|
|
||||||
try {
|
try {
|
||||||
cleanerField = direct.getClass().getDeclaredField("cleaner");
|
Class<?> cls = Class.forName("sun.nio.ch.DirectBuffer", false, PlatformDependent0.class.getClassLoader());
|
||||||
cleanerField.setAccessible(true);
|
Method method = cls.getMethod("cleaner");
|
||||||
Cleaner cleaner = (Cleaner) cleanerField.get(direct);
|
if ("sun.misc.Cleaner".equals(method.getReturnType().getName())) {
|
||||||
cleaner.clean();
|
directBufferFreeable = true;
|
||||||
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
cleanerField = null;
|
// We don't have sun.nio.ch.DirectBuffer.cleaner().
|
||||||
}
|
}
|
||||||
logger.debug("java.nio.ByteBuffer.cleaner: {}", cleanerField != null? "available" : "unavailable");
|
logger.debug("sun.nio.ch.DirectBuffer.cleaner(): {}", directBufferFreeable? "available" : "unavailable");
|
||||||
|
|
||||||
Field addressField;
|
Field addressField;
|
||||||
try {
|
try {
|
||||||
addressField = Buffer.class.getDeclaredField("address");
|
addressField = Buffer.class.getDeclaredField("address");
|
||||||
addressField.setAccessible(true);
|
addressField.setAccessible(true);
|
||||||
if (addressField.getLong(ByteBuffer.allocate(1)) != 0) {
|
if (addressField.getLong(ByteBuffer.allocate(1)) != 0) {
|
||||||
|
// A heap buffer must have 0 address.
|
||||||
addressField = null;
|
addressField = null;
|
||||||
} else {
|
} else {
|
||||||
direct = ByteBuffer.allocateDirect(1);
|
ByteBuffer direct = ByteBuffer.allocateDirect(1);
|
||||||
if (addressField.getLong(direct) == 0) {
|
if (addressField.getLong(direct) == 0) {
|
||||||
|
// A direct buffer must have non-zero address.
|
||||||
addressField = null;
|
addressField = null;
|
||||||
}
|
}
|
||||||
Cleaner cleaner = (Cleaner) cleanerField.get(direct);
|
|
||||||
cleaner.clean();
|
|
||||||
}
|
}
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
|
// Failed to access the address field.
|
||||||
addressField = null;
|
addressField = null;
|
||||||
}
|
}
|
||||||
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
|
logger.debug("java.nio.Buffer.address: {}", addressField != null? "available" : "unavailable");
|
||||||
|
|
||||||
Unsafe unsafe;
|
Unsafe unsafe;
|
||||||
if (addressField != null && cleanerField != null) {
|
if (addressField != null && directBufferFreeable) {
|
||||||
try {
|
try {
|
||||||
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
Field unsafeField = Unsafe.class.getDeclaredField("theUnsafe");
|
||||||
unsafeField.setAccessible(true);
|
unsafeField.setAccessible(true);
|
||||||
@ -104,6 +105,7 @@ final class PlatformDependent0 {
|
|||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
} catch (Throwable cause) {
|
} catch (Throwable cause) {
|
||||||
|
// Unsafe.copyMemory(Object, long, Object, long, long) unavailable.
|
||||||
unsafe = null;
|
unsafe = null;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -111,6 +113,7 @@ final class PlatformDependent0 {
|
|||||||
// Let's just pretend unsafe is unavailable for overall simplicity.
|
// Let's just pretend unsafe is unavailable for overall simplicity.
|
||||||
unsafe = null;
|
unsafe = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNSAFE = unsafe;
|
UNSAFE = unsafe;
|
||||||
|
|
||||||
if (unsafe == null) {
|
if (unsafe == null) {
|
||||||
@ -144,19 +147,6 @@ final class PlatformDependent0 {
|
|||||||
UNSAFE.throwException(t);
|
UNSAFE.throwException(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void freeDirectBufferUnsafe(ByteBuffer buffer) {
|
|
||||||
try {
|
|
||||||
Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
|
|
||||||
if (cleaner == null) {
|
|
||||||
throw new IllegalArgumentException(
|
|
||||||
"attempted to deallocate the buffer which was allocated via JNIEnv->NewDirectByteBuffer()");
|
|
||||||
}
|
|
||||||
cleaner.clean();
|
|
||||||
} catch (Throwable t) {
|
|
||||||
// Nothing we can do here.
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void freeDirectBuffer(ByteBuffer buffer) {
|
static void freeDirectBuffer(ByteBuffer buffer) {
|
||||||
if (!(buffer instanceof DirectBuffer)) {
|
if (!(buffer instanceof DirectBuffer)) {
|
||||||
return;
|
return;
|
||||||
|
Loading…
Reference in New Issue
Block a user