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-*.optionsfiles (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 = -Xmxto 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'
