CleanerJava25 Class — netty Architecture
Architecture documentation for the CleanerJava25 class in CleanerJava25.java from the netty codebase.
Entity Profile
Dependency Diagram
graph TD 7ab188e3_8847_b494_ece0_39be8ad2e276["CleanerJava25"] 65e55f1e_37ee_36e5_4c41_4fe66a648def["CleanerJava25.java"] 7ab188e3_8847_b494_ece0_39be8ad2e276 -->|defined in| 65e55f1e_37ee_36e5_4c41_4fe66a648def 751eba07_7c52_5eae_9dc5_a33d68166a95["isSupported()"] 7ab188e3_8847_b494_ece0_39be8ad2e276 -->|method| 751eba07_7c52_5eae_9dc5_a33d68166a95 e255d12a_e22f_df1a_aceb_4df26362cfcd["CleanableDirectBuffer()"] 7ab188e3_8847_b494_ece0_39be8ad2e276 -->|method| e255d12a_e22f_df1a_aceb_4df26362cfcd 71eda40f_742e_a4f1_463b_cb43318bc270["freeDirectBuffer()"] 7ab188e3_8847_b494_ece0_39be8ad2e276 -->|method| 71eda40f_742e_a4f1_463b_cb43318bc270
Relationship Graph
Source Code
common/src/main/java/io/netty/util/internal/CleanerJava25.java lines 31–224
final class CleanerJava25 implements Cleaner {
private static final InternalLogger logger;
private static final MethodHandle INVOKE_ALLOCATOR;
static {
boolean suitableJavaVersion;
if (System.getProperty("org.graalvm.nativeimage.imagecode") != null) {
// native image supports this since 25, but we don't use PlatformDependent0 here, since
// we need to initialize CleanerJava25 at build time.
String v = System.getProperty("java.specification.version");
try {
suitableJavaVersion = Integer.parseInt(v) >= 25;
} catch (NumberFormatException e) {
suitableJavaVersion = false;
}
// also need to prevent initializing the logger at build time
logger = null;
} else {
// Only attempt to use MemorySegments on Java 25 or greater, because of the following JDK bugs:
// - https://bugs.openjdk.org/browse/JDK-8357145
// - https://bugs.openjdk.org/browse/JDK-8357268
suitableJavaVersion = PlatformDependent0.javaVersion() >= 25;
logger = InternalLoggerFactory.getInstance(CleanerJava25.class);
}
MethodHandle method;
Throwable error;
if (suitableJavaVersion) {
try {
// Here we compose and construct a MethodHandle that takes an 'int' capacity argument,
// and produces a 'CleanableDirectBufferImpl' instance.
// The method handle will create a new shared Arena instance, allocate a MemorySegment from it,
// convert the MemorySegment to a ByteBuffer and a memory address, and then pass both the Arena,
// the ByteBuffer, and the memory address to the CleanableDirectBufferImpl constructor,
// returning the resulting object.
//
// Effectively, we are recreating the following the Java code through MethodHandles alone:
//
// Arena arena = Arena.ofShared();
// MemorySegment segment = arena.allocate(size);
// return new CleanableDirectBufferImpl(
// (AutoCloseable) arena,
// segment.asByteBuffer(),
// segment.address());
//
// First, we need the types we'll use to set this all up.
Class<?> arenaCls = Class.forName("java.lang.foreign.Arena");
Class<?> memsegCls = Class.forName("java.lang.foreign.MemorySegment");
Class<CleanableDirectBufferImpl> bufCls = CleanableDirectBufferImpl.class;
// Acquire the private look up, so we can access the package-private 'CleanableDirectBufferImpl'
// constructor.
MethodHandles.Lookup lookup = MethodHandles.lookup();
// ofShared.type() = ()Arena
MethodHandle ofShared = lookup.findStatic(arenaCls, "ofShared", methodType(arenaCls));
// Try to access shared Arena which might fail on GraalVM 25.0.0 if not enabled
// See https://github.com/netty/netty/issues/15762
Object shared = ofShared.invoke();
((AutoCloseable) shared).close();
// allocate.type() = (Arena,long)MemorySegment
MethodHandle allocate = lookup.findVirtual(arenaCls, "allocate", methodType(memsegCls, long.class));
// asByteBuffer.type() = (MemorySegment)ByteBuffer
MethodHandle asByteBuffer = lookup.findVirtual(memsegCls, "asByteBuffer", methodType(ByteBuffer.class));
// address.type() = (MemorySegment)long
MethodHandle address = lookup.findVirtual(memsegCls, "address", methodType(long.class));
// bufClsCtor.type() = (AutoCloseable,ByteBuffer,long)CleanableDirectBufferImpl
MethodHandle bufClsCtor = lookup.findConstructor(bufCls,
methodType(void.class, AutoCloseable.class, ByteBuffer.class, long.class));
// The 'allocate' method takes a 'long' capacity, but we'll be providing an 'int'.
// Explicitly cast the 'long' to 'int' so we can use 'invokeExact'.
// allocateInt.type() = (Arena,int)MemorySegment
MethodHandle allocateInt = MethodHandles.explicitCastArguments(allocate,
methodType(memsegCls, arenaCls, int.class));
// Use the 'asByteBuffer' and 'address' methods as a filter, to transform the constructor into a method
// that takes two MemorySegment arguments instead of a ByteBuffer and a long argument.
// ctorArenaMemsegMemseg.type() = (Arena,MemorySegment,MemorySegment)CleanableDirectBufferImpl
MethodHandle ctorArenaMemsegMemseg = MethodHandles.explicitCastArguments(
MethodHandles.filterArguments(bufClsCtor, 1, asByteBuffer, address),
Source
Frequently Asked Questions
What is the CleanerJava25 class?
CleanerJava25 is a class in the netty codebase, defined in common/src/main/java/io/netty/util/internal/CleanerJava25.java.
Where is CleanerJava25 defined?
CleanerJava25 is defined in common/src/main/java/io/netty/util/internal/CleanerJava25.java at line 31.
Analyze Your Own Codebase
Get architecture documentation, dependency graphs, and domain analysis for your codebase in minutes.
Try Supermodel Free