Configuring Off-Heap Store
The off-heap store extends the in-memory store to memory outside the of the object heap. This store, which is not subject to Java garbage collection (GC), is limited only by the amount of RAM available.
Because off-heap data is stored in bytes, only data that is Serializable is suitable for the off-heap store. Any non serializable data overflowing to the OffHeapMemoryStore is simply removed, and a WARNING level log message emitted.
Since serialization and deserialization take place on putting and getting from the off-heap store, it is theoretically slower than the memory store. This difference, however, is mitigated when GC involved with larger heaps is taken into account.
Allocating Direct Memory in the JVM
The off-heap store uses the direct-memory portion of the JVM. You must allocate sufficient direct memory for the off-heap store by using the JVM property MaxDirectMemorySize.
For example, to allocate 2GB of direct memory in the JVM:
java -XX:MaxDirectMemorySize=2G ...
Since direct memory may be shared with other processes, allocate at least 256MB (or preferably 1GB) more to direct memory than will be allocated to the off-heap store.
Note the following about allocating direct memory:
If you configure off-heap memory but do not allocate direct memory with
-XX:MaxDirectMemorySize, the default value for direct memory depends on your version of your JVM. Oracle HotSpot has a default equal to maximum heap size (-Xmx value), although some early versions may default to a particular value.
MaxDirectMemorySize must be added to the local node's startup environment.
Direct memory, which is part of the Java process heap, is separate from the object heap allocated by -Xmx. The value allocated by
MaxDirectMemorySizemust not exceed physical RAM, and is likely to be less than total available RAM due to other memory requirements.
The amount of direct memory allocated must be within the constraints of available system memory and configured off-heap memory.
The maximum amount of direct memory space you can use depends on the process data model (32-bit or 64-bit) and the associated operating system limitations, the amount of virtual memory available on the system, and the amount of physical memory available on the system.
Using Off-Heap Store with 32-bit JVMs
The amount of heap-offload you can achieve is limited by addressable memory. 64-bit systems can allow as much memory as the hardware and operating system can handle, while 32-bit systems have strict limitations on the amount of memory that can be effectively managed.
For a 32-bit process model, the maximum virtual address size of the process is typically 4GB, though most 32-bit operating systems have a 2GB limit. The maximum heap size available to Java is lower still due to particular operating-system (OS) limitations, other operations that may run on the machine (such as mmap operations used by certain APIs), and various JVM requirements for loading shared libraries and other code. A useful rule to observe is to allocate no more to off-heap memory than what is left over after -Xmx is set. For example, if you set -Xmx3G, then off-heap should be no more than 1GB. Breaking this rule may not cause an OutOfMemoryError on startup, but one is likely to occur at some point during the JVM's life.
If Java GC issues are afflicting a 32-bit JVM, then off-heap store can help. However, note the following:
Everything has to fit in 4GB of addressable space. If 2GB of heap is allocated (with -Xmx2g) then at most are 2GB left for off-heap data.
The JVM process requires some of the 4GB of addressable space for its code and shared libraries plus any extra Operating System overhead.
Allocating a 3GB heap with -Xmx, as well as 2047MB of off-heap memory, will not cause an error at startup, but when it's time to grow the heap an OutOfMemoryError is likely.
If both -Xms3G and -Xmx3G are used with 2047MB of off-heap memory, the virtual machine will start but then complain as soon as the off-heap store tries to allocate the off-heap buffers.
Some APIs, such as java.util.zip.ZipFile on a 1.5 JVM, may <mmap> files in memory. This will also use up process space and may trigger an OutOfMemoryError.
Configuring the Off-Heap Store
If an off-heap store is configured, the corresponding memory store overflows to that off-heap store. Configuring an off-heap store can be done either through XML or programmatically. With either method, the off-heap store is configured on a per-cache basis.
Declarative Configuration
The following XML configuration creates an off-heap cache with an in-heap store (maxEntriesLocalHeap) of 10,000 elements which overflow to a 1-gigabyte off-heap area.
<ehcache updateCheck="false" monitoring="off" dynamicConfig="false">
<defaultCache maxEntriesLocalHeap="10000"
eternal="true"
memoryStoreEvictionPolicy="LRU"
statistics="false" />
<cache name="sample-offheap-cache"
maxEntriesLocalHeap="10000"
eternal="true"
memoryStoreEvictionPolicy="LRU"
overflowToOffHeap="true"
maxBytesLocalOffHeap="1G"/>
</ehcache>
The configuration options are:
overflowToOffHeap
Values may be true or false. When set to true, enables the cache to utilize off-heap memory storage to improve performance. Off-heap memory is not subject to Java GC cycles and has a size limit set by the Java property MaxDirectMemorySize. The default value is false.
maxBytesLocalOffHeap
Sets the amount of off-heap memory available to the cache and is in effect only if overflowToOffHeap is true. The minimum amount that can be allocated is 1MB. There is no maximum.
For more information on sizing data stores, see
Sizing Storage Tiers.
Note:
You should set maxEntriesLocalHeap to at least 100 elements when using an off-heap store to avoid performance degradation. Lower values for maxEntriesLocalHeap trigger a warning to be logged.
Programmatic Configuration
The equivalent cache can be created using the following programmatic configuration:
public Cache createOffHeapCache()
{
CacheConfiguration config = new CacheConfiguration("sample-offheap-cache", 10000)
.overflowToOffHeap(true).maxBytesLocalOffHeap("1G");
Cache cache = new Cache(config);
manager.addCache(cache);
return cache;
}