RFR: 8361099: Shenandoah: Improve heap lock contention by using CAS for memory allocation [v5]

Kelvin Nilsen kdnilsen at openjdk.org
Wed Nov 5 22:31:23 UTC 2025


On Wed, 5 Nov 2025 19:00:03 GMT, Kelvin Nilsen <kdnilsen at openjdk.org> wrote:

>> Xiaolong Peng has updated the pull request with a new target base due to a merge or a rebase. The pull request now contains 135 commits:
>> 
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - format
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - Merge branch 'master' into cas-alloc-1
>>  - Move ShenandoahHeapRegionIterationClosure to shenandoahFreeSet.hpp
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - Fix errors caused by renaming ofAtomic to AtomicAccess
>>  - Merge branch 'openjdk:master' into cas-alloc-1
>>  - ... and 125 more: https://git.openjdk.org/jdk/compare/2f613911...e6bfef05
>
> src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp line 848:
> 
>> 846: HeapWord* ShenandoahFreeSet::allocate_with_affiliation(Iter& iterator, ShenandoahAffiliation affiliation, ShenandoahAllocRequest& req, bool& in_new_region) {
>> 847:   for (idx_t idx = iterator.current(); iterator.has_next(); idx = iterator.next()) {
>> 848:     ShenandoahHeapRegion* r = _heap->get_region(idx);
> 
> I wonder if we could refine this a little bit.  When the region is moved into the "directly allocatable" set, wouldn't we remove it from its partition?  Then, we wouldn't have to test for !r->reserved_for_direct_allocation() here because the iterator wouldn't produce it. 
> 
> We could maybe replace this test with an assert that !r->reserved_for_direct_allocation().

Same issue in other uses of the allocation iterator.

> src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp line 2280:
> 
>> 2278: }
>> 2279: 
>> 2280: class DirectAllocatableRegionRefillClosure final : public ShenandoahHeapRegionIterationClosure {
> 
> I don't think we want to subclass ShenandoahHeapRegionIterationClosure here.  That iterates over all 2000 regions.  We only want to iterate over the 13 Directly allocatable regions.  Maybe we don't even need/want a closure iterator here.  We could just write a loop.

I think we should be borrowing from this code when replenishing the regions that are ready to be retired:

  if (_partitions.alloc_from_left_bias(ShenandoahFreeSetPartitionId::Mutator)) {
    // Allocate from low to high memory.  This keeps the range of fully empty regions more tightly packed.
    // Note that the most recently allocated regions tend not to be evacuated in a given GC cycle.  So this
    // tends to accumulate "fragmented" uncollected regions in high memory.
    ShenandoahLeftRightIterator iterator(&_partitions, ShenandoahFreeSetPartitionId::Mutator);
    return allocate_from_regions(iterator, req, in_new_region);
  }

  // Allocate from high to low memory. This preserves low memory for humongous allocations.
  ShenandoahRightLeftIterator iterator(&_partitions, ShenandoahFreeSetPartitionId::Mutator);
  return allocate_from_regions(iterator, req, in_new_region);

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/26171#discussion_r2495761580
PR Review Comment: https://git.openjdk.org/jdk/pull/26171#discussion_r2496372013


More information about the hotspot-gc-dev mailing list