Aligning the Serial collector with ZGC
Thomas Schatzl
thomas.schatzl at oracle.com
Wed Oct 2 06:47:52 UTC 2024
Hi,
On 28.09.24 00:55, Kirk Pepperdine wrote:
> Hi Thomas,
>
> I wanted to respond to all of your comments but I thought better of it
> given one response deserves it’s own email. The focus is mostly on that
> one question.
>
>> >
>> > - Introduce an adaptive size policy that takes into account memory and
>> > CPU pressure along with global memory pressure.
>> > - Heap should be large enough to minimize GC overhead but not
>> > large enough to trigger OOM.
>>
>> (probably meant "small enough" the second time)
>
> I actually did mean large but in the context of OOM killer…. But to your
> point, smaller but avoid OOME is also a concern.
>
>>
>> > - Introduce -XX:SerialPressure=[0-100] to support this work.
>>
>> (Fwiw, regards to the other discussion, I agree that if we have a flag
>> with the same "meaning" across collectors it might be useful to use
>> the same name).
>
> I think we have deadly agreement on this one.
>
>>
>> > - introduce a smoothing algorythm to avoid excessive small
>> > resizes.
>>
>> One option is to split this further into parts:
>>
>> * list what actions Serial GC could do in reaction to memory pressure
>> on an abstract level, and which make sense; from that see what
>> functionality is needed.
>
> I built a chart some time ago and this is an expanded version of it.
>
[...]
>
> Some of my thoughts used to construct the table.
>
[...]
> All of the resizing decisions need to be moderated by the availability
> of (global) memory. If global memory is scarce, then the decision should
> favour releasing (uncommitting) memory. This may come at the expense of
> higher GC overhead. Resizing to smaller pool sizes is not without risk
> and in the case of young, both high global memory pressure and high
> allocation pressure add to the risk.
>
Thank you for sharing your detailed thoughts.
>
>
>>
>> * provide functionality that tries to keep some kind of GC/mutator
>> time ratio; I would start with looking at G1 does because Serial GC's
>> behaviour is probably closer to G1 than ZGC, but ymmv.
>> (Obviously improvements are welcome :))
>
> I would agree.
Here's some old code for implementing
https://bugs.openjdk.org/browse/JDK-8238687: Uncommit at every GC that
improves a bit on the current G1 policy which implements both signalling
for under/over-cpu usage ratio, which is maybe better (documented) than
the existing code.
https://github.com/openjdk/jdk/compare/master...tschatzl:jdk:investigate-memory-uncommit-every-gc-only
[...]
>> > - Introduce manageable flag SoftMaxHeapSize to define a target heap
>> > size nd set the default max heap size to 100% of available.
>>
>> I am a bit torn about SoftMaxHeapSize in Serial GC. What do you
>> envision that Serial GC would do when the SoftMaxHeapSize has been
>> reached, and what if old gen occupancy permanently stays above that value?
>
> At the moment, SoftMaxHeapSize is an implementation in Z. I’d first like
> to pull a (rough) spec out of the implementation and then try to answer
> your question. It’s currently not clear to me how this should work with
> any collector.
>>
>> The usefulness of SoftMaxHeapSize kind of relies on having a minimally
>> invasive old gen collection that tries to get old gen usage back below
>> that value.
>
> Well, the LDS is what it is and running a speculative collection would
> likely clean up (prematurely) promoted transients… but that’s about it.
> Whereas it would clean both transients and floating garbage for the
> concurrent collectors. I’m not at fan of speculative collections given
> all of the time I’ve spent getting rid of them :-) IMO, a DGC triggered
> full collections was rarely necessary (all overhead with very little
> return). This also applied to the G1 patch that speculatively ran to
> counter to-space overflows and it also applied to running a young gen
> prior to remark with CMS collector. Long story sort, loads of extra
> overhead with very little to no payback.
SoftMaxHeapSize is a bit different as it is non-speculative but
supposedly based on the users intent.
>> Serial GC has no "minimally invasive" way to collect old generation.
>> It is either Full GC or nothing. This is the only option for Serial,
>> but always doing Full collections after reaching that threshold seems
>> very heavy handed, expensive and undesirable to me (ymmv).
>>
>> That reaction would follow the spirit of the flag though.
>>
>> Maybe at the small heaps Serial GC targets, this makes sense, and full
>> gc is not that costly anyway.
>
> Yeah, for small heap this shouldn’t be a big deal. But this is one of
> the reasons why I believe we should treat young and old separately. We
> can cheaply and safely return memory from young gen and leave the sizing
> of tenured to when a full is really needed. I grant you that this may
> not be very timely but I’m not sure that we need this to happen on
> demand… I think we can wait for natural cycles to take their course.
> But, maybe I’m wrong on this point. We plan to experiment with this.
Please do and report back.
>>
>> It might be useful to enumerate what actions could be performed on
>> global pressure.
>
> That’s in the table…
>
>>
>> > - Add in the ability to uncommit memory (to reduce global memory
>> > pressure).
>> >
>>
>> The following imo outlines a compdoneletely separate idea, and should
>> be discussed separately:
>>
>> >
>> > While working through the details of this work I noted that there
>> > appear to opportunities to offer new defaults for other settings. For
>> > example, [...]
>>
>> That seems to be some more elaborate way of finding "optimal"
>> generation size for a given heap size (which may follow from what the
>> gc/mutator time ratio algorithm gives you).
>
> I’m trying to apply my years of experience tuning 100s of collectors
> across 100s of applications.
>
Very much appreciated.
Hth,
Thomas
More information about the hotspot-gc-dev
mailing list