RFR: 8372543: Shenandoah: undercalculated the available size when soft max takes effect
William Kemper
wkemper at openjdk.org
Wed Dec 3 18:56:56 UTC 2025
On Wed, 3 Dec 2025 02:02:18 GMT, Rui Li <duke at openjdk.org> wrote:
> Detailed math and repro see https://bugs.openjdk.org/browse/JDK-8372543.
>
> Currently in shenandoah, when deciding whether to have gc, how we calculate available size is:
>
>
> available = (Xmx * (100 - ShenandoahEvacReserve) / 100) - used
> soft_tail = Xmx - soft_max
> if (available - soft_tail < ShenandoahMinFreeThreshold * soft_max) // trigger gc
>
>
> The if condition `available - soft_tail` will be reduced to: `-(ShenandoahEvacReserve/100) * Xmx - used + soft_max`, which means when soft max is the same, the larger Xmx is, the less free size the app would have and the more gc it would have, which does not make sense, especially for the case where the app is mostly idle. This caused one of our internal customers experienced frequent gc with minimal workload, when soft max heap size was set way lower than Xmx.
>
>
> Suggested fix: when deciding when to trigger gc, use logic similar to below:
>
> mutator_soft_capacity = soft_max * (100 - ShenandoahEvacReserve) / 100;
> available = mutator_soft_capacity - used;
> if (available < mutator_soft_capacity) // trigger gc
> ```
>
> -------
> This change also improved gc logging:
>
> Before:
>
> [6.831s][info][gc ] Trigger: Free (52230K) is below minimum threshold (52428K)
> [6.831s][info][gc,free ] Free: 1587M, Max: 1024K regular, 1539M humongous, Frag: 2%
> external, 18% internal; Used: 352M, Mutator Free: 1940 Collector Reserve: 103M, Max: 1024K; Used: 0B
>
>
> After:
>
> [8.358s][info][gc ] Trigger: Free (Soft mutator free) (51498K) is below minimum threshold (52428K)
> [8.358s][info][gc,free ] Whole heap stats: Total free: 1509M, Total used: 401M, Max free in a single region:
> 1024K, Max humongous: 1490M; Frag stats: External: 0%, Internal: 21%; Mutator freeset stats: Partition count:
> 1911, Reserved: 1509M, Max free available in a single region: 1024K; Collector freeset stats: Partition count:
> 122, Reserved: 102M, Max free available in a single region: 1024K;
A few nits. Thank you for adding a test case for this!
src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp line 240:
> 238: size_t allocated = _space_info->bytes_allocated_since_gc_start();
> 239:
> 240: log_debug(gc)("should_start_gc calculation: available: %zu%s, soft_max_capacity: %zu%s"
Can we add `ergo` tag to this message? Let's use the `PROPERFMT` and `PROPERFMTARGS` macros here and in other log messages we're changing.
src/hotspot/share/gc/shenandoah/heuristics/shenandoahAdaptiveHeuristics.cpp line 258:
> 256: size_t min_threshold = min_free_threshold();
> 257: if (available < min_threshold) {
> 258: log_trigger("Free (Soft mutator free) (%zu%s) is below minimum threshold (%zu%s)",
Changing this will break some log parsers, do we really need this?
src/hotspot/share/gc/shenandoah/heuristics/shenandoahCompactHeuristics.cpp line 52:
> 50: size_t capacity = ShenandoahHeap::heap()->soft_max_capacity();
> 51: size_t available = _space_info->soft_available();
> 52: size_t allocated = _space_info->bytes_allocated_since_gc_start();
This shadows `bytes_allocated` below. Let's just use one variable for this.
src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp line 3209:
> 3207: log_freeset_stats(ShenandoahFreeSetPartitionId::Mutator, ls);
> 3208: log_freeset_stats(ShenandoahFreeSetPartitionId::Collector, ls);
> 3209: if (_heap->mode()->is_generational()) {log_freeset_stats(ShenandoahFreeSetPartitionId::OldCollector, ls);}
Suggestion:
if (_heap->mode()->is_generational()) {
log_freeset_stats(ShenandoahFreeSetPartitionId::OldCollector, ls);
}
src/hotspot/share/gc/shenandoah/shenandoahFreeSet.hpp line 632:
> 630: size_t get_usable_free_words(size_t free_bytes) const;
> 631:
> 632: void log_freeset_stats(ShenandoahFreeSetPartitionId partition_id, LogStream& ls);
`log_freeset_stats` should probably be `private`.
-------------
Changes requested by wkemper (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/28622#pullrequestreview-3536428634
PR Review Comment: https://git.openjdk.org/jdk/pull/28622#discussion_r2586232667
PR Review Comment: https://git.openjdk.org/jdk/pull/28622#discussion_r2586234993
PR Review Comment: https://git.openjdk.org/jdk/pull/28622#discussion_r2586237553
PR Review Comment: https://git.openjdk.org/jdk/pull/28622#discussion_r2586243946
PR Review Comment: https://git.openjdk.org/jdk/pull/28622#discussion_r2586247150
More information about the shenandoah-dev
mailing list