From 3c2dbdb5db30bc0ce691f29aadff55c3f18dd60b Mon Sep 17 00:00:00 2001 From: Norman Maurer Date: Wed, 5 Sep 2018 07:23:03 +0200 Subject: [PATCH] NioEventLoop should also use our special SelectionKeySet on Java9 and later. (#8260) Motivation: In Java8 and earlier we used reflection to replace the used key set if not otherwise told. This does not work on Java9 and later without special flags as its not possible to call setAccessible(true) on the Field anymore. Modifications: - Use Unsafe to instrument the Selector with out special set when sun.misc.Unsafe is present and we are using Java9+. Result: NIO transport produce less GC on Java9 and later as well. --- .../util/internal/PlatformDependent.java | 9 ++++++++ .../util/internal/PlatformDependent0.java | 4 ++++ .../io/netty/channel/nio/NioEventLoop.java | 22 ++++++++++++++++--- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent.java b/common/src/main/java/io/netty/util/internal/PlatformDependent.java index 64d740aaf3..fa38e8921d 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent.java @@ -29,6 +29,7 @@ import org.jctools.util.Pow2; import org.jctools.util.UnsafeAccess; import java.io.File; +import java.lang.reflect.Field; import java.lang.reflect.Method; import java.nio.ByteBuffer; import java.nio.ByteOrder; @@ -567,6 +568,14 @@ public final class PlatformDependent { PlatformDependent0.putLong(data, index, value); } + public static void putObject(Object o, long offset, Object x) { + PlatformDependent0.putObject(o, offset, x); + } + + public static long objectFieldOffset(Field field) { + return PlatformDependent0.objectFieldOffset(field); + } + public static void copyMemory(long srcAddr, long dstAddr, long length) { PlatformDependent0.copyMemory(srcAddr, dstAddr, length); } diff --git a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java index cf3c471273..df45d1614a 100644 --- a/common/src/main/java/io/netty/util/internal/PlatformDependent0.java +++ b/common/src/main/java/io/netty/util/internal/PlatformDependent0.java @@ -568,6 +568,10 @@ final class PlatformDependent0 { UNSAFE.putLong(data, BYTE_ARRAY_BASE_OFFSET + index, value); } + static void putObject(Object o, long offset, Object x) { + UNSAFE.putObject(o, offset, x); + } + static void copyMemory(long srcAddr, long dstAddr, long length) { // Manual safe-point polling is only needed prior Java9: // See https://bugs.openjdk.java.net/browse/JDK-8149596 diff --git a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java index e36e24a279..a95d514c19 100644 --- a/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java +++ b/transport/src/main/java/io/netty/channel/nio/NioEventLoop.java @@ -43,7 +43,6 @@ import java.util.Collection; import java.util.Iterator; import java.util.Queue; import java.util.Set; -import java.util.concurrent.Callable; import java.util.concurrent.Executor; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; @@ -188,8 +187,8 @@ public final class NioEventLoop extends SingleThreadEventLoop { }); if (!(maybeSelectorImplClass instanceof Class) || - // ensure the current selector implementation is what we can instrument. - !((Class) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) { + // ensure the current selector implementation is what we can instrument. + !((Class) maybeSelectorImplClass).isAssignableFrom(unwrappedSelector.getClass())) { if (maybeSelectorImplClass instanceof Throwable) { Throwable t = (Throwable) maybeSelectorImplClass; logger.trace("failed to instrument a special java.util.Set into: {}", unwrappedSelector, t); @@ -207,6 +206,23 @@ public final class NioEventLoop extends SingleThreadEventLoop { Field selectedKeysField = selectorImplClass.getDeclaredField("selectedKeys"); Field publicSelectedKeysField = selectorImplClass.getDeclaredField("publicSelectedKeys"); + if (PlatformDependent.javaVersion() >= 9 && PlatformDependent.hasUnsafe()) { + // Let us try to use sun.misc.Unsafe to replace the SelectionKeySet. + // This allows us to also do this in Java9+ without any extra flags. + long selectedKeysFieldOffset = PlatformDependent.objectFieldOffset(selectedKeysField); + long publicSelectedKeysFieldOffset = + PlatformDependent.objectFieldOffset(publicSelectedKeysField); + + if (selectedKeysFieldOffset != -1 && publicSelectedKeysFieldOffset != -1) { + PlatformDependent.putObject( + unwrappedSelector, selectedKeysFieldOffset, selectedKeySet); + PlatformDependent.putObject( + unwrappedSelector, publicSelectedKeysFieldOffset, selectedKeySet); + return null; + } + // We could not retrieve the offset, lets try reflection as last-resort. + } + Throwable cause = ReflectionUtil.trySetAccessible(selectedKeysField, true); if (cause != null) { return cause;