RFR: JDK-8307314: Implementation: Generational Shenandoah (Experimental) [v9]
Thomas Stuefe
stuefe at openjdk.org
Wed Jun 7 07:50:20 UTC 2023
On Wed, 7 Jun 2023 00:39:52 GMT, Kelvin Nilsen <kdnilsen at openjdk.org> wrote:
>> OpenJDK Colleagues:
>>
>> Please review this proposed integration of Generational mode for Shenandoah GC under https://bugs.openjdk.org/browse/JDK-8307314.
>>
>> Generational mode of Shenandoah is enabled by adding `-XX:+UnlockExperimentalVMOptions -XX:ShenandoahGCMode=generational` to a command line that already specifies ` -XX:+UseShenandoahGC`. The implementation automatically adjusts the sizes of old generation and young generation to efficiently utilize the entire heap capacity. Generational mode of Shenandoah resembles G1 in the following regards:
>>
>> 1. Old-generation marking runs concurrently during the time that multiple young generation collections run to completion.
>> 2. After old-generation marking completes, we perform a sequence of mixed collections. Each mixed collection combines collection of young generation with evacuation of a portion of the old-generation regions identified for collection based on old-generation marking information.
>> 3. Unlike G1, young-generation collections and evacuations are entirely concurrent, as with single-generation Shenandoah.
>> 4. As with single-generation Shenandoah, there is no explicit notion of eden and survivor space within the young generation. In practice, regions that were most recently allocated tend to have large amounts of garbage and these regions tend to be collected with very little effort. Young-generation objects that survive garbage collection tend to accumulate in regions that hold survivor objects. These regions tend to have smaller amounts of garbage, and are less likely to be collected. If they survive a sufficient number of young-generation collections, the “survivor” regions are promoted into the old generation.
>>
>> We expect to refine heuristics as we gain experience with more production workloads. In the future, we plan to remove the “experimental” qualifier from generational mode, at which time we expect that generational mode will become the default mode for Shenandoah.
>>
>> **Testing**: We continuously run jtreg tiers 1-4 + hotspot_gc_shenandoah, gcstress, jck compiler, jck runtime, Dacapo, SpecJBB, SpecVM, Extremem, HyperAlloc, and multiple AWS production workload simulators. We test on Linux x64 and aarch64, Alpine x64 and aarch64, macOS x64 and aarch64, and Windows x64.
>
> Kelvin Nilsen has updated the pull request incrementally with one additional commit since the last revision:
>
> Update copyright notices
> Thanks Thomas for the feedback:
>
> These proposed changes represent improvements to both Generational and Non-generational modes of operation. We can revert if that is desired, or we can specialize Generational versions of these parameters so that they can have different values in different modes, but here is a bit of background. We've done considerable testing on a variety of synthetic workloads and some limited testing on production workloads. As we move towards upstream integration, we expect this will help us gain exposure to more production workloads. The following changes were based on results of this testing:
> <snip>
Hi Kelvin,
thanks for the thorough explanations!
It is a pity that these valuable insights are buried in a GH discussion and these changes inside such a large patch. I also looked at the originating patch in openjdk/shenandoah, which I assume is your development repo for Shenandoah (?).
Could I convince you to adapt the JBS issue process in the shenandoah repo (so, opening an issue on JBS, with some clear explanation, then fixing the bug)? Roman convinced me of this for the Lilliput repository, and now I think the added work is well worth it. JBS is a treasure trove of insights, if filled with care, and can help us for many years.
Some more questions about `ShenandoahFullGCThreshold`:
I am looking at the nice ASCII art in `ShenandoahControlThread::service_concurrent_normal_cycle`. IIUC, the cycle goes:
Concurrent GC -> Alloc failure -> n x Degenerated GC -> Alloc Failure -> Full GC
right? So the change is now in how often we try a degenerated GC before falling back to a full GC?
With GenShen, does a degenerated GC still collect only the young regions? And only FullGC does collect all regions?
Are comment and ASCII-art still correct for GenShen? E.g. the comment says:
// If second allocation failure happens during Degenerated GC cycle (for example, when GC
// tries to evac something and no memory is available), cycle degrades to Full GC.
Is "second allocation failure" correct? Since even before this patch, we tried three times before falling back to a Full GC.
Thank you,
Thomas
-------------
PR Comment: https://git.openjdk.org/jdk/pull/14185#issuecomment-1580127311
More information about the hotspot-dev
mailing list