Performance Zone is brought to you in partnership with:

Peter is a DZone MVB and is not an employee of DZone and has posted 158 posts at DZone. You can read more from them at their website. View Full User Profile

sun.misc.Unsafe and Off Heap Memory

01.20.2014
| 8566 views |
  • submit to reddit

Overview

The class sun.misc.Unsafe allows you to many of the things you shouldn't be able to do in Java, but are still useful in very specific cases.  It is to be avoided 99% of the time, however there are rare occasions where this is the only solution which makes sense.

This blog considers how it has been using in OpenHFT and what functionality I would like to see in Java 9. In particular, accessing large amount of memory without impacting the GC can be done this way. Sharing memory between processes, without significant overhead, can only be done this way in Java.

Allocating and freeing off heap memory.

public native long allocateMemory();
public native void freeMemory(long address);
These two method allow you to allocate any size of off heap memory.  It is not limited to Integer.MAX_VALUE bytes and you get raw memory where you can apply bounds checking as you need to. e.g. Bytes.writeUTF(String) calculates the length of the encoded string, and checks that the whole string would fit, once, not on each byte.

Java-Lang uses the same internal Cleaner class that DirectByteBuffer uses to ensure the memory is freed.  Ideally this wouldn't be so internal.

Raw access to memory

public native Xxx getXxx(Object, long offset);
public native void putXxx(Object, long offset);

In both cases, the Object is null when dealing with off heap memory and the offset is just the address. This allows you to perform RAW memory access using single machine code instructions for the JVMs which threat these as intrinsics.  This significantly improves performance for memory access. The problem with this raw approach is you have to manage the layout of your fields in your data structures yourself.  The Java-Lang library addresses this by allowing you to define an interface of getters and setters (even for object types like String and enums) and it will generate the implementation at runtime. i.e. you can access the getter/setters without needing to know the "objects" are off heap.

Thread safe access to memory

public native Xxx getVolatileXxx(Object, long offset);
public native void putOrderedXxx(Object, long offset);

These two sets of methods allow you to use a field as volatile with a lazy set.  The lazy set is faster for the setting thread but could result in the same thread reading an old value if done too quickly.  The solution to this is don't read a value you just wrote. These methods are particularly useful when sharing data between processes.

CAS operations

public native boolean compareAndSwapXxxx(Object, long offset, Xxx expected, Xxx setTo) 

This method is essential for building locks off heap.  In particular it is the most efficient way to share data in a thread safe manner between processes.  In tests I have done on a Haswell processor i7-4500, the round trip latency of two processes on the same machine is typically;
  • TCP               - 9 micro-seconds.
  • FileLocks       - 5.5 micro-seconds.
  • CAS               - 0.12 micro-seconds.
  • Ordered write - 0.02 micro-seconds (Half round trip, if this pattern can be used)

On heap object allocation

 public native Object allocateInstance(Class clazz);

When deserializing a class, you want to reconstitute the values in that class the way it was when serialized.  This doesn't work well with the current constructors as noted in JEP 187: Serialization 2.0 A work around for this is to avoid the constructors entirely and create an instance without calling one. This assumes much about trusting the data you have, but it has the advantage of being easy to use and places no assumptions about which constructors you have.

Conclusion

It has often been noted that embedded databases, without a network overhead, can out perform distributed databases in term of latency.  I believe the next generation of low latency databases will give the performance of embedded and be shared between processes and give both update and query response times well below a micro-second. I see no reason these should not be implemented in Java.  For Java users, a native interface will perform best as it doesn't need JNI or translation from a C view of the world to a Java view.


Published at DZone with permission of Peter Lawrey, author and DZone MVB. (source)

(Note: Opinions expressed in this article and its replies are the opinions of their respective authors and not those of DZone, Inc.)

Comments

Peter Karussell replied on Mon, 2014/01/20 - 2:15am

Nice! BTW: Instead static for all the methods you meant native?

Peter Lawrey replied on Mon, 2014/01/20 - 5:17pm

Good point. They are native, but not JNI in most cases.  They are actually intrinsics. They don't use the instance really either as it's stateless.

Peter Verhas replied on Tue, 2014/01/21 - 8:17am

The need for the functions I acknowledge and I agree. To have these calls standard I oppose.

I would not support allocation of memory off heap for many reasons. Instead the GC algorithms have to be fine tuned so that the allocation of huge memory does not affect adversely the performance. To embrace the high performance features that you reach now using Unsafe, new run time may provide functions on special objects that are just delivering the higher level feature.

Formulating it the other way, run-time functionality should not expose operation lower than the level of the embracing language. In this sense Java is a high level language.

I say that even though I myself was using instance allocation of Unsafe in some of my hobby projects (djcproxy).

Peter Lawrey replied on Tue, 2014/01/21 - 8:48am in response to: Peter Verhas

The Java libraries should be full features enough that you shouldn't need to use Unsafe.  With this in mind there is a group to discuss an JEP to provide replacement functionality to not need Unsafe.

https://groups.google.com/forum/?hl=en-GB#!forum/jep-off-heap

Peter Karussell replied on Wed, 2014/01/22 - 5:20am in response to: Peter Lawrey

Do you know a (open source) library that already does this - as I would like to have some Unsafe equivalent on Android for memory access/allocation!

Comment viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.