[id='off_heap_memory']
= Off-Heap Memory

{brandname} stores cache entries in JVM heap memory by default.
You can configure {brandname} to use off-heap storage, which means your data occupies native memory outside the managed JVM memory space with the following benefits:

* Uses less memory than JVM heap memory for the same amount of data.
* Can improve overall JVM performance by avoiding Garbage Collector (GC) runs.

However, there are some trade-offs with off-heap storage; for example, JVM heap dumps do not show entries stored in off-heap memory.

The following diagram illustrates the memory space for a JVM process where {brandname} is running:

.JVM memory space
image::offheap.svg[Illustration of JVM memory space]

.JVM heap memory

The heap is divided into young and old generations that help keep referenced Java objects and other application data in memory.
The GC process reclaims space from unreachable objects, running more frequently on the young generation memory pool.

When {brandname} stores cache entries in JVM heap memory, GC runs can take longer to complete as you start adding data to your caches.
Because GC is an intensive process, longer and more frequent runs can degrade application performance.

.Off-heap memory

Off-heap memory is native available system memory outside JVM memory management.
The _JVM memory space_ diagram shows the `Metaspace` memory pool that holds class metadata and is allocated from native memory.
The diagram also represents a section of native memory that holds {brandname} cache entries.

[discrete]
== Storing data off-heap

When you add entries to off-heap caches, {brandname} dynamically allocates native memory to your data.

{brandname} hashes the serialized `byte[]` for each key into buckets that are similar to a standard Java `HashMap`.
Buckets include address pointers that {brandname} uses to locate entries that you store in off-heap memory.

[NOTE]
====
{brandname} determines equality of Java objects in off-heap storage using the serialized byte[] representation of each object instead of the object instance.
====

The following diagram shows a set of keys with names, the hash for each key and bucket array of address pointers, as well as the entries with the name and phone number:

.Memory address pointers for keys
image::offheap_hashmap.svg[Illustration of keys and bucket array of memory address pointers]

When key hashes collide, {brandname} links entries.
In the _Memory address pointers for keys_ diagram, if the `William Clay` and `Luke Cage` keys have the same hash, then the first entry added to the cache is the first element in the bucket.

[NOTE]
====
Even though {brandname} stores cache entries in native memory, run-time operations require JVM heap representations of those objects.
For instance, `cache.get()` operations read objects into heap memory before returning.
Likewise, state transfer operations hold subsets of objects in heap memory while they take place.
====

[discrete]
== Memory overhead

Memory overhead is the additional memory that {brandname} uses to store entries.
For off-heap storage, {brandname} uses 25 bytes for each entry in the cache.

When you use eviction to create a bounded off-heap data container, memory overhead increases to a total of 61 bytes because {brandname} creates an additional linked list to track entries in the cache and perform eviction.

[discrete]
== Data consistency

{brandname} uses an array of locks to protect off-heap address spaces.
The number of locks is twice the number of cores and then rounded to the nearest power of two.
This ensures that there is an even distribution of `ReadWriteLock` instances to prevent write operations from blocking read operations.
