Goal: make Cassandra’s memory use predictable by pinning the JVM heap and (optionally) capping off-heap/direct memory. This guide targets Ubuntu 24.04 + Cassandra 5.0.x + OpenJDK 17.
What are the defaults?
- Heap (
-Xms
,-Xmx
): By default, Cassandra auto-sizes the heap at startup to ½ of physical RAM, capped at ~31 GB when using G1GC. (Keeping the heap ≤31 GB preserves compressed OOPs.) Both Xms and Xmx are set to that auto-calculated value unless you override them. - Direct/off-heap (
-XX:MaxDirectMemorySize
): If you don’t set it, the JVM picks it automatically (internally derived; effectively “no explicit cap”). Many operators choose to set an explicit cap for predictability. - *Where configs live (C 4.x/5.x)**: Modern Cassandra uses the
jvm-*.options
files (e.g.,jvm17-server.options
) for JVM flags; these are the supported place to pin heap/GC.
Quick checks
java --version # should show OpenJDK 17
cassandra -v # 5.0.x
Cassandra 5.x on Java 17 reads JVM flags from /etc/cassandra/jvm17-server.options
.
- Pick sensible numbers
Rules of thumb (start here, then load-test):
- Set
-Xms = -Xmx
to avoid heap resize pauses. - Leave ≈15–20% of RAM for the OS and native memory.
- If you increase heap, consider increasing the direct memory cap as well.
Small host example (popular choice):
- Heap →
-Xms2G -Xmx2G
- Direct cap →
-XX:MaxDirectMemorySize=1G
(raise later if you observe direct-buffer pressure)
It’s normal for process RSS to exceed just the heap (native libs, thread stacks, mmap, JIT, etc.).
- Edit JVM options (Java 17)
Open /etc/cassandra/jvm17-server.options
and add your lines just before the ### JPMS
section (i.e., right after these two commented lines):
#-XX:ParallelGCThreads=16
#-XX:ConcGCThreads=16
Add:
# Heap sizing (set min = max)
-Xms2G
-Xmx2G
# Optional: cap direct/off-heap memory (Bloom filters, index summaries, compression metadata, Netty)
-XX:MaxDirectMemorySize=1G
- Restart & verify
sudo systemctl restart cassandra
# From Cassandra’s view
nodetool info | egrep 'Heap Memory|Off Heap|Non Heap'
# Confirm JVM flags actually in use (requires jcmd)
pid=$(pgrep -f 'org.apache.cassandra.service.CassandraDaemon' | head -n1)
sudo jcmd "$pid" VM.flags | egrep 'Xms|Xmx|MaxDirectMemorySize'