RFR: 8321816: GenShen: Provide a minimum amount of time for an old collection to run [v4]

William Kemper wkemper at openjdk.org
Thu Dec 21 03:11:12 UTC 2023


On Thu, 21 Dec 2023 01:30:28 GMT, Y. Srinivas Ramakrishna <ysr at openjdk.org> wrote:

>> William Kemper has updated the pull request incrementally with one additional commit since the last revision:
>> 
>>   Update stale comment
>
> src/hotspot/share/gc/shenandoah/shenandoahRegulatorThread.cpp line 67:
> 
>> 65: }
>> 66: 
>> 67: void ShenandoahRegulatorThread::regulate_young_and_old_cycles() {
> 
> I am wondering if it might not be simpler and clearer to write this method as:
> 
> 
> ...
> while (!should_terminate()) {
>   switch (mode) {
>      case SCT::none : {
>         // no collection is in progress
>         // 1. check and start a global collection if needed
>         if (should_unload_classes() && start_global_cycle()) {
>           log_info...
>         } else if (start_old_cycle()) {
>            // 2. else check and start an old cycle
>            log_info...
>         } else if (start_young_cycle()) {
>             // 3. else check and start a young cycle
>            log_info...
>         }
>         break;
>      }
>      case SCT::servicing_old: {
>          // if an old collection is in progress, check if a young
>          // collection is needed. We can't start a global collection
>          // in this state, even if one is needed.
>          if (start_young_cycle()) {
>            log_info...
>          }
>          break;
>       }
>       default: // fall through
>    }
>    // sleep a tad before next check; sleep duration inversely proportional to allocation rate
>    regulator_sleep();   // My worry is that heuristics says wait for old increment and we sleep longer than that? May be that's not an issue?
> }
> ...
> 
> 
> The rest of the checks etc. seem already to be done in the `start_...` methods from what I can tell.
> 
> I may have missed some subtlety though.

When regulating young and old cycles (i.e., generational mode), the regulator overrides the global heuristics decision to start a global cycle. In other modes, whether or not to unload classes is decided _after_ a cycle is started. However, the generational mode can only unload classes in a _global_ cycle, so we use the oom in metaspace to _trigger_ a global cycle (even if the global heuristic would not otherwise trigger a cycle).

The other subtlety here is that old cycles are only started when a young cycle wants to run. Each old cycle is preceded by a young "bootstrap" cycle, so the young heuristic trigger is still satisfied. This was meant to avoid the situation where old cycles are triggered shortly after a young cycle - which runs an unproductive "bootstrap" cycle. This is why we check the young heuristic and then the old heuristic before starting an old cycle.

Your comment about starting a global cycle (to unload classes) even during an old cycle is interesting though. There's no specific reason why we couldn't interrupt and abandon the old cycle in this case, but I think that's a change for another PR.

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

PR Review Comment: https://git.openjdk.org/shenandoah/pull/371#discussion_r1433404818


More information about the shenandoah-dev mailing list