Skip navigation

Java 24 and sun.misc.Unsafe

Did you know this page is automatically generated from a Github Wiki page? You can improve it by yourself here!

Java 24 integrated JEP 498 and started printing warnings to the console, when sun.misc.Unsafe memory-access methods are first used.

Netty has historically been relying on these methods to more efficiently work with native (off-heap) memory. This means applications that use Netty, and run on Java 24 or greater, may see these warnings.

Netty 4.1 and Unsafe

To avoid these warnings being printed when using Netty 4.1, users have to explicitly allow Unsafe memory access using the following command line argument for the JVM:

--sun-misc-unsafe-memory-access=allow

Netty 4.1.120 and 4.1.121

Netty 4.1.120 and 4.1.121 disabled its use of sun.misc.Unsafe by default when running on Java 24 or greater (PR #14943), to avoid these warnings showing up for our users.

This changed default is reverted in Netty 4.1.122 (PR #15296), so the behavior is restored to what it was in Netty 4.1.119.

The reason we decided to revert the change in behavior is that 1) the performance regression was greater than anticipated, and 2) making use of JNI (such as when using our native transports or native TLS implementation) produced a similar warning, but with no way for us to work around it in the Netty 4.x versions.

Netty 4.2 and Unsafe

Netty 4.2.0 and 4.2.1 take no special precautions, and produce warnings the same as Netty 4.1 (excluding 4.1.120 and 4.1.121) does.

Netty 4.2.2 adds support for using MemorySegment APIs to avoid relying on Unsafe (PR #15231).

What Netty uses Unsafe for

Netty and its native transports need native (off-heap) memory to move data faster to and from the operating system, i.e. without copying data into and out of the heap as well.

To effectively work with native memory, Netty needs a way to not only allocate memory, but also deallocate it as soon as it's done using it. Netty needs Unsafe to access the cleaner instance inside the direct ByteBuffers. The cleaner is the mechanism used to deallocate the memory in direct ByteBuffer instances.

When Unsafe is not available to Netty, then the ByteBuffer cleaner is also not available to Netty, and it instead has to rely on the garbage collector for releasing the memory.

The garbage collector runs in response to heap memory pressure, but direct buffers do not produce much memory pressure on the heap. This causes native memory to be released after a greater delay than strictly necessary, which in turn increases memory usage. The JDK attempts to work around this by occasionally running the garbage collector explicitly when allocating new direct ByteBuffer instances, and then sleeping for 100 milliseconeds.

This behavior, the increased explicit GC and the 100 milliseconds sleep, is unacceptable to Netty. We cannot accept sleeping or any other blocking operation in the event loop thread.

For this reason, Netty will use heap buffers by default when the direct ByteBuffer cleaner is not available.

As a consequence, heap usage can be greatly increased on systems where Unsafe is not available, and the time and CPU resources spent on garbage collection likewise increase, with reduced system-wide performance as a result.

Last retrieved on 05-Jun-2025