When All Else Fails: Using “the Unsafe”

Sometimes you have to hack. You just have to. Don’t listen to XKCD. You don’t always regret hacking. On our blog, we’ve shown a couple of hacks before:

But we’ve just been scratching the surface. Our friends at ZeroTurnaround / RebelLabs have recently published an awesome article about how to use “the Unsafe”. The sun.misc.Unsafe class to directly access memory in Java. While the first page introduces us to the Unsafe object itself and how to access it through reflection …

public static Unsafe getUnsafe() {
    try {
        Field f = Unsafe.class
        return (Unsafe) f.get(null);
    } catch (Exception e) { 
        /* ... */ 

… subsequent sections nicely explain how to map “unsafe” memory access methods to addressing a Class in memory, of objects in memory

// If you're daring, go manipulate the heap directly!
Object helperArray[] = new Object[1];
helperArray[0] = targetObject;
long baseOffset = 
long addressOfObject =
    unsafe.getLong(helperArray, baseOffset);

However, don’t think it’s so easy. In order to manipulate the Java heap directly, you will need to understand a lot about the various fields and flags in class headers, and you’ll always need to remember to distinguish between 32-bit and 64-bit JVMs.

7 thoughts on “When All Else Fails: Using “the Unsafe”

  1. When All Else Fails: Using “the Unsafe” … will also. This is not without reason why the name is “unsafe”. The major problem is that the addresses acquired via unsafe will not change when a parallel executing GC just moves the objects. And then you end up with a code that will fail the same old, dreadful and miserable way. Core dump. No more information.

    Was it that we changed C++ for Java?

    1. Was it that we changed C++ for Java?

      It depends on what you’re doing. Consider the following code snippet from com.google.common.primitives.UnsignedBytes$LexicographicalComparatorHolder$UnsafeComparator$1, for instance:

       * Compare 8 bytes at a time. Benchmarking shows comparing 8 bytes at a
       * time is no slower than comparing 4 bytes at a time even on 32-bit.
       * On the other hand, it is substantially faster on 64-bit.
      for (int i = 0; i < minWords * Longs.BYTES; i += Longs.BYTES) {
        long lw = theUnsafe.getLong(left, BYTE_ARRAY_BASE_OFFSET + (long) i);
        long rw = theUnsafe.getLong(right, BYTE_ARRAY_BASE_OFFSET + (long) i);
        long diff = lw ^ rw;

      I trust their benchmark really showed significant improvements in the above code. And I suspect that a single call to getLong() is atomic, so the GC won’t interfere here.

      It’s not always easy to get it right, and there are terrible ways to get it wrong. But it’s not necessarily a bad idea to use the “unsafe”

      1. You are right. Nevertheless the use of unsafe should very much be limited. Not an everyday task and I would not pass code directly using it in an enterprise application.

        Any blog referring to use of unsafe should press very much how dangerous this can be.

        1. Doesn’t the name “unsafe” and the fact that we need to access it through reflection keep us from using it, the reasonable and responsible engineers that we are? :-)

      2. I do trust Google’s benchmark, but unless you do this in a long loop, the performance benefits will be minimal.

        If you do it in a long loop, and profiling has shown that it makes your app unacceptably slow, chances are it isn’t the only expensive operation, and it makes sense to use JNI to call a library you specifically write in portable C.

        Unsafe has one more problem: it’s not thread-safe. In your bytes example above, you have no way to use Unsafe ina thread-safe way. Therefore, using Unsafe in one place nails down several design constraints which will give you headaches later.

        I remember what a guy named A. J. Riel said in a book which IMO every programmer should read: whenever you feel like you need multiple inheritance, assume you don’t and try to prove otherwise. I’d apply similar thinking to using Unsafe.

Leave a Reply