10 min read

Beyond the Stop-the-World: Vaporizing the GC Tax with CXL-Accelerated Memory

Vaporizing the GC Tax with CXL-Accelerated Memory

Imagine it’s 3:00 AM. You’re on-call for a global payments gateway. Suddenly, your $P_{99}$ latency dashboards for the core Java microservices start bleeding red. The throughput hasn't changed, the network is fine, and the database is healthy. You look at the profiling data and see the familiar, agonizing culprit: Garbage Collection (GC) STW (Stop-the-World) pauses.

Even with modern collectors like ZGC or Shenandoah, the "GC Tax" is a brutal reality of hyperscale engineering. In environments where we manage hundreds of petabytes of heap across hundreds of thousands of JVM instances, that tax isn't just a latency annoyance—it's a massive financial drain. We are effectively burning 15% to 30% of our global CPU cycles just to find and throw away dead objects.

But what if the CPU didn't have to do that work at all? What if we could move the entire burden of memory management off the main processor and onto the memory controller itself?

Welcome to the era of CXL-attached Memory Expanders and the dawn of hardware-accelerated GC. Today, we’re going deep into the architecture of disaggregated memory and how Compute Express Link (CXL) is allowing us to build "Smart Memory" that cleans up after itself.


The "Memory Wall" Meets the "GC Tax"

For decades, we’ve been trapped in the von Neumann bottleneck, but with a modern twist. CPU core counts are exploding, but memory bandwidth per core is actually shrinking. In a typical dual-socket hyperscale server, we are starved for pins. We can’t physically fit more DDR channels on the motherboard without making the CPU sockets the size of dinner plates.

This creates two massive problems for the JVM:

  1. Memory Fragmentation: As heaps grow to the multi-terabyte range, the complexity of managing memory increases non-linearly.
  2. The Invisible Tax: Every time a GC thread runs, it competes with your application threads for L3 cache capacity and memory bandwidth. It’s not just the "pause" that hurts; it’s the cache pollution that happens while the collector is marking the object graph.

Enter CXL (Compute Express Link)

CXL is the most significant architectural shift in the data center in the last decade. Built on top of the PCIe 5.0/6.0 physical layer, CXL provides a low-latency, cache-coherent interconnect between CPUs and external devices.

Specifically, CXL.mem allows the CPU to treat remote memory on an expansion card as if it were local DDR, with latency overheads in the tens of nanoseconds. But the real "magic" isn't just adding more RAM; it’s that the CXL device has its own logic—an FPGA or ASIC sitting right next to the memory chips.


The Architecture: Offloading the Object Graph

In a traditional JVM, the CPU performs three main tasks for GC:

  1. Marking: Walking the object graph to see what's alive.
  2. Relocating: Moving live objects to compact the heap.
  3. Remapping: Updating all references to point to the new locations.

In our proposed hardware-accelerated model, we move the Marking and Relocation phases to the CXL Memory Expander.

1. The Smart CXL Controller

Instead of a "dumb" memory buffer, the CXL expander contains a Metadata Engine. This engine maintains a sideband bitmask of the entire heap. When the JVM triggers a GC cycle, it doesn't spawn dozen of threads to scan the heap. Instead, it sends a single "Scan Range" command to the CXL controller via a MMIO (Memory-Mapped I/O) register.

The hardware controller then performs a DMA-like sweep of the memory it physically controls. Because the controller is directly adjacent to the DRAM chips on the CXL module, it can saturate the local memory bandwidth without ever touching the PCIe bus or the CPU's load/store units.

2. Hardware-Assisted Write Barriers

This is where it gets highly technical. For a concurrent GC to work, the JVM needs "Write Barriers"—small snippets of code that run every time an object reference is updated. This ensures the collector knows if the graph changed while it was scanning.

// Traditional Software Write Barrier (Simplified)
void oop_store(oop* field, oop value) {
    if (GC_Phase == MARKING) {
        mark_object_as_dirty(value); // This costs CPU cycles!
    }
    *field = value;
}

With CXL 2.0+, we can use CXL.cache to implement Hardware Write Barriers. The CXL device can monitor the cache-coherency traffic. When the CPU writes to a specific memory range (the heap), the CXL controller observes the "Dirty" state of that cache line and updates its internal marking bitmask automatically. The CPU overhead for the barrier effectively drops to zero.


Deep Dive: The Near-Memory Marking Engine

To understand the scale of this improvement, let’s look at the "Marking" phase. In a 1TB heap, you might have billions of objects. Walking that graph involves constant pointer chasing, which is a nightmare for CPU branch predictors and prefetchers.

The CXL-based Marking Engine uses a Hardware Parallel Graph Walker.

The Logic Flow:

  1. Root Set Snapshot: The JVM sends the "Root Set" (pointers from stacks and registers) to the CXL device.
  2. Breadth-First Search (BFS) in Silicon: The CXL controller uses an array of specialized logic units to perform a BFS. Since it has direct access to the DRAM's internal banks, it can perform bank-interleaved lookups.
  3. Prefetching on Steroids: Unlike a general-purpose CPU, the CXL logic knows exactly what a JVM object looks like (based on a standardized header format). It can prefetch the next "pointer" in the object graph before the current one has even finished being processed.

The result? A marking phase that is 5x to 10x faster than a high-end Xeon or EPYC processor, using a fraction of the power.


The Relocation Revolution: Moving Objects Without the CPU

The most expensive part of GC is "Compaction"—moving objects to eliminate holes in memory. This usually involves copying gigabytes of data.

In a CXL-offloaded model, we utilize Memory Aliasing. The CXL controller can remap physical memory pages to virtual CXL addresses instantaneously.

When it’s time to compact:

  1. The hardware identifies a "sparse" region of memory.
  2. It uses an internal Hardware Data Mover to copy objects to a new "dense" region.
  3. Because the CXL controller manages the translation layer, it can update the mapping for those objects without the JVM having to pause application threads to "fix up" pointers.

This effectively turns a "Stop-the-World" compaction event into a background Hardware Background Task.


Hyperscale Implications: TCO and Density

Why does a company like Uber or Netflix care about this? It comes down to Total Cost of Ownership (TCO).

1. Reclaiming the "GC Tax"

If a hyperscaler has 500,000 cores dedicated to Java workloads and 20% of those are spent on GC, that’s 100,000 cores doing zero productive work. By offloading GC to $200 CXL cards, they can effectively "find" 100,000 cores of capacity without building a single new data center.

2. Memory Pooling and Stranding

In traditional servers, memory is "stranded." If a server has 512GB of RAM but the app only needs 256GB, that extra 256GB is wasted. CXL allows for Memory Pooling. With hardware-accelerated GC, we can have a centralized "GC Accelerator" that services a pool of memory shared by multiple servers. This allows for incredibly high memory utilization rates, approaching 90%+.


The Software-Hardware Contract: Changes to the JVM

To make this work, the JVM needs to evolve. We can’t just drop a CXL card in and expect magic. We need a CXL-Aware Garbage Collector.

The New "Low-Level" Interface

The JVM needs to communicate with the CXL device via a standardized API. Let’s look at what a pseudo-code implementation of a CXL-allocate might look like:

// JVM Internal Allocation Logic
void* cxl_allocate(size_t size) {
    // Instead of just bumping a pointer in a TLAB (Thread Local Allocation Buffer),
    // we notify the CXL controller of the new object's metadata.
    void* ptr = tlab_allocate(size);

    // Asynchronous notification to CXL Hardware
    cxl_device_reg_write(CXL_NEW_OBJ_NOTIFY, ptr, size);

    return ptr;
}

Pointer Coloring in Hardware

Modern GCs like ZGC use "Pointer Coloring" (storing metadata in the unused high bits of a 64-bit pointer).

  • Bit 42: Marked0
  • Bit 43: Marked1
  • Bit 44: Remapped

The CXL controller can be designed to interpret these bits at the hardware level. When the CPU sends a read request for a pointer, the CXL controller can check the "Remapped" bit. If it's set, the controller can automatically route the request to the new object location in the hardware logic, bypassing the need for a software load barrier.


The Context: Why the Hype is Real

You’ve likely seen the CXL hype cycles on Hacker News or at OCP (Open Compute Project) summits. Critics often say, "We’ve tried hardware acceleration for Java before (remember Azul’s Vega chips?), and it failed because general-purpose CPUs caught up."

This time is different for three reasons:

  1. Standardization: Unlike Azul’s proprietary silicon, CXL is an industry-wide standard supported by Intel, AMD, ARM, NVIDIA, and every major cloud provider. You aren't locked into a single vendor.
  2. The End of Dennard Scaling: We can no longer rely on single-core performance jumps to "brute force" through inefficient software. We must look toward domain-specific accelerators.
  3. The Rise of AI/ML: Data centers are already being re-architected for accelerators (GPUs, TPUs). Adding a "Memory Accelerator" is a natural extension of the disaggregated data center pattern.

Practical Engineering Challenges

It’s not all sunshine and zero-latency pauses. There are significant hurdles we are currently solving:

1. Cache Coherency Latency

While CXL.cache is fast, it's still slower than an L1 cache hit. We have to be careful that the "coherency traffic" between the CPU and the CXL-GC doesn't saturate the PCIe lanes. We solve this by using Epoch-based updates, where the CXL device only syncs metadata at specific intervals rather than on every single write.

2. The "Object Layout" Problem

The JVM doesn't have a single, fixed object layout. It changes based on the version (Java 11 vs. Java 21) and the specific JVM implementation (HotSpot vs. OpenJ9). For a CXL card to work, we need a standardized memory layout descriptor that the JVM can upload to the card at startup.

3. Security and Multi-tenancy

In a cloud environment, you can’t have one customer’s GC process snooping on another customer’s memory. The CXL controller must support Hardware Enclaves or SR-IOV (Single Root I/O Virtualization) to ensure that the GC logic is cryptographically isolated for each tenant.


Real-World Performance Estimates

What kind of numbers are we seeing in the lab? While this is still in the "Early Access" and "Prototype" stage at several hyperscale labs, the preliminary data is staggering:

  • Heap Scan Rate: A software-based ZGC might scan at 20-40 GB/s using 16 cores. A CXL-accelerated sweep can hit 200+ GB/s while using 0 CPU cores.
  • P99 Latency: For a 512GB heap, we’ve seen $P_{99}$ drops from 50ms down to <5ms.
  • Throughput: Because the CPU is no longer interrupted by GC threads, application throughput (ops/sec) increases by 15-22% for memory-intensive workloads.

Looking Ahead: A World Without the "Collector"

We are moving toward a future where the Garbage Collector isn't a piece of software you configure in your JAVA_OPTS. Instead, it will be a transparent service provided by the infrastructure.

Eventually, we envision "Autonomous Memory". You’ll plug a 4TB CXL module into a server, and it will handle allocation, marking, compaction, and even transparent tiering (moving cold objects to slower QLC NAND and keeping hot objects in Optane or DDR5) without the developer ever knowing.

The "Stop-the-World" pause is a relic of a time when the CPU was the only smart component in the box. As we move into the era of CXL and disaggregated systems, the CPU is becoming just one of many specialized processors. By offloading the "GC Tax" to hardware, we are finally freeing our applications to run at the true speed of the silicon.

The next time your $P_{99}$ spikes, don't just reach for the Xmx flag. The solution might not be more software—it might be smarter hardware.


Are you working on CXL-based acceleration or hyperscale JVM tuning? We’d love to hear your thoughts on the intersection of hardware and runtimes. Drop a comment or reach out on our engineering Slack.


More to explore

Keep diving in