diff a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp --- a/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp +++ b/src/hotspot/share/gc/shenandoah/shenandoahFreeSet.cpp @@ -3126,11 +3126,23 @@ } HeapWord* ShenandoahFreeSet::allocate(ShenandoahAllocRequest& req, bool& in_new_region) { shenandoah_assert_heaplocked(); - if (ShenandoahHeapRegion::requires_humongous(req.size())) { + // A freshly allocated mutator object is not yet hashed and may grow by one word + // when an identity hash-code is injected during a future GC copy. Classify it by + // its potential expanded size so an object that could outgrow a region is placed + // as humongous from the start, rather than allocated as a regular object and then + // needing to become humongous after it grows. Every other request carries an + // already-final size: + // - a GC copy (_alloc_shared_gc*) uses an already-expanded copy_size(), + // - a CDS allocation (_alloc_cds) requests a raw archive range; its objects are + // written at their final, already hash-expanded size (copy_size_cds) and are + // not grown at load time, + // - a LAB buffer (TLAB/GCLAB/PLAB, bounded by max_tlab_size_words()) never grows. + const bool may_expand_for_hash = (req.type() == ShenandoahAllocRequest::_alloc_shared); + if (ShenandoahHeapRegion::requires_humongous(req.size(), may_expand_for_hash)) { switch (req.type()) { case ShenandoahAllocRequest::_alloc_shared: case ShenandoahAllocRequest::_alloc_shared_gc: in_new_region = true; return allocate_contiguous(req, /* is_humongous = */ true);