Apache Cassandra heap changes affect every read, write, and compaction on a node because the JVM heap shares physical memory with off-heap structures and the operating system page cache. A heap that is too small increases garbage-collection pressure, while a heap that is too large can take memory away from file cache and direct buffers.

Cassandra calculates heap at startup from /etc/cassandra/cassandra-env.sh unless static -Xms and -Xmx flags are already active in jvm-server.options. For the usual Cassandra 5 Java 11 or Java 17 G1GC path, set MAX_HEAP_SIZE and leave HEAP_NEWSIZE unset; HEAP_NEWSIZE belongs to older CMS tuning.

Choose the target after checking node RAM, workload, and recent garbage-collection behavior. Apache guidance keeps the heap at least 2 GB and no more than half of system RAM, and each restart should be rolled through one node at a time so the ring remains available while the new maximum is verified.

Steps to tune Apache Cassandra heap size:

  1. Check cluster state from the Cassandra node selected for tuning.
    $ nodetool status
    Datacenter: datacenter1
    =======================
    Status=Up/Down
    |/ State=Normal/Leaving/Joining/Moving
    --  Address    Load       Tokens  Owns (effective)  Host ID                               Rack
    UN  10.0.0.11  6.42 GiB   16      100.0%            8f4f6e2d-9f74-4f5a-a85f-43df5d4fcb21  rack1

    Start with one UN node. If the ring already shows down, joining, leaving, or moving nodes, finish that maintenance before changing heap on another node.

  2. Check the current heap maximum before editing.
    $ nodetool info
    ID                     : 8f4f6e2d-9f74-4f5a-a85f-43df5d4fcb21
    Gossip active          : true
    Native Transport active: true
    Load                   : 6.42 GiB
    ##### snipped #####
    Heap Memory (MB)       : 514.18 / 1024.00
    Off Heap Memory (MB)   : 312.00
    Data Center            : datacenter1
    Rack                   : rack1
    Exceptions             : 0

    The value after the slash is the current maximum heap in megabytes.

  3. Open the server JVM options file and check for active static heap flags.
    $ sudoedit /etc/cassandra/jvm-server.options

    If active -Xms or -Xmx lines are present, set both to the same target there or remove them before using MAX_HEAP_SIZE in /etc/cassandra/cassandra-env.sh. Commented lines beginning with # do not override cassandra-env.sh.

  4. Open the Cassandra environment file.
    $ sudoedit /etc/cassandra/cassandra-env.sh

    Package installs usually use /etc/cassandra/cassandra-env.sh. Tarball installs keep the same file under the extracted conf directory.

  5. Set the target heap size near the existing heap comments.
    MAX_HEAP_SIZE="2G"
    # Leave HEAP_NEWSIZE unset when the node uses G1GC.

    Replace 2G with the tested value for the node. Leave memory for the operating system page cache, direct memory, memtables, caches, and compaction work instead of assigning most RAM to the Java heap.

  6. Restart the selected Cassandra node.
    $ sudo systemctl restart cassandra

    Restart one node at a time and wait for the node to return to the ring before changing the next node.
    Related: How to check Apache Cassandra service status

  7. Confirm the Cassandra service is active.
    $ sudo systemctl is-active cassandra
    active
  8. Confirm the node returned to UN state.
    $ nodetool status
    Datacenter: datacenter1
    =======================
    Status=Up/Down
    |/ State=Normal/Leaving/Joining/Moving
    --  Address    Load       Tokens  Owns (effective)  Host ID                               Rack
    UN  10.0.0.11  6.42 GiB   16      100.0%            8f4f6e2d-9f74-4f5a-a85f-43df5d4fcb21  rack1

    If the node does not return to UN, inspect /var/log/cassandra/system.log before moving to another node.
    Related: How to view Apache Cassandra logs

  9. Verify the running JVM uses the new heap maximum.
    $ nodetool info
    ID                     : 8f4f6e2d-9f74-4f5a-a85f-43df5d4fcb21
    Gossip active          : true
    Native Transport active: true
    Load                   : 6.42 GiB
    ##### snipped #####
    Heap Memory (MB)       : 623.98 / 2048.00
    Off Heap Memory (MB)   : 318.00
    Data Center            : datacenter1
    Rack                   : rack1
    Exceptions             : 0

    The maximum should match the configured heap after unit conversion. A 2G heap appears as about 2048.00 MB.

  10. Repeat the same change on the next Cassandra node after the current node stays UN under normal client traffic.