From d30e6633ff0d5ca085b5faf2526185cea54dc4f6 Mon Sep 17 00:00:00 2001 From: samlightfoot Date: Sat, 21 Feb 2026 11:50:32 +0000 Subject: [PATCH] Force GC before direct memory measurements for ZGC compatibility Generational ZGC (JDK 21 default) only processes PhantomReferences during major collections, which may not trigger during short test runs. This causes DirectByteBuffer Cleaners to not fire, leaving ~63MB of stale direct memory that inflates TOTAL_CAPACITY and fails the assertion. Force System.gc() via nodetool before each measurement to ensure a major collection runs and reference processing completes. --- largecolumn_test.py | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/largecolumn_test.py b/largecolumn_test.py index d7d4a696c7..9bd1d2288a 100644 --- a/largecolumn_test.py +++ b/largecolumn_test.py @@ -1,6 +1,8 @@ import pytest import re import logging +import subprocess +import time from dtest import Tester @@ -69,16 +71,28 @@ def test_cleanup(self): # Now run the full stack to warm up internal caches/pools LARGE_COLUMN_SIZE = 1024 * 1024 * 63 self.stress_with_col_size(cluster, node1, LARGE_COLUMN_SIZE) - after1stLargeStress = self.directbytes(node1) + after1stLargeStress = self.directbytes_post_gc(node1) logger.info("After 1st large column stress, direct memory: {0}".format(after1stLargeStress)) # Now run the full stack to see how much memory is allocated for the second "large" columns request self.stress_with_col_size(cluster, node1, LARGE_COLUMN_SIZE) - after2ndLargeStress = self.directbytes(node1) + after2ndLargeStress = self.directbytes_post_gc(node1) logger.info("After 2nd large column stress, direct memory: {0}".format(after2ndLargeStress)) # We may allocate direct memory proportional to size of a request # but we want to ensure that when we do subsequent calls the used direct memory is not growing - diff = int(after2ndLargeStress) - int(after1stLargeStress) + diff = after2ndLargeStress - after1stLargeStress logger.info("Direct memory delta: {0}".format(diff)) assert diff < LARGE_COLUMN_SIZE + + def directbytes_post_gc(self, node): + """Trigger GC and wait for the Cleaner thread to release DirectByteBuffers. + + Generational ZGC (JDK 21) only processes PhantomReferences during major + collections which may not run during short tests. After GC, the Cleaner + daemon thread decrements TOTAL_CAPACITY asynchronously, so we sleep to + allow it to complete. + """ + subprocess.check_call(['jcmd', str(node.pid), 'GC.run']) + time.sleep(3) + return int(self.directbytes(node)) \ No newline at end of file