diff --git a/runtime/gc_vlhgc/CopyForwardScheme.cpp b/runtime/gc_vlhgc/CopyForwardScheme.cpp index a52ce215967..f4d57fc8934 100644 --- a/runtime/gc_vlhgc/CopyForwardScheme.cpp +++ b/runtime/gc_vlhgc/CopyForwardScheme.cpp @@ -535,13 +535,22 @@ MM_CopyForwardScheme::postProcessRegions(MM_EnvironmentVLHGC *env) while (NULL != (region = regionIterator.nextRegion())) { MM_MemoryPool *pool = region->getMemoryPool(); if (region->_copyForwardData._evacuateSet) { - if (region->isEden()) { + /* Use logicalAge == 0 to classify both evacuate and survivor regions consistently. + * This includes true Eden regions (ADDRESS_ORDERED type) as well as non-Eden regions + * that have logicalAge 0 (ADDRESS_ORDERED_MARKED, i.e. survivors from the previous GMP + * at compact group 0). Both kinds of age-0 regions produce age-0 survivor regions + * (logicalAge of the destination is derived from the source compact group), so counting + * them uniformly on both sides keeps _edenSurvivorRegionCount / _edenEvacuateRegionCount + * a meaningful ratio. + */ +// if (region->isEden()) { + if (0 == region->getLogicalAge()) { static_cast(env->_cycleState)->_vlhgcIncrementStats._copyForwardStats._edenEvacuateRegionCount += 1; } else { static_cast(env->_cycleState)->_vlhgcIncrementStats._copyForwardStats._nonEdenEvacuateRegionCount += 1; } } else if (region->isFreshSurvivorRegion()) { - /* check Eden Survivor Regions */ + /* check Eden Survivor Regions — logicalAge == 0 matches the evacuate classification above */ if (0 == region->getLogicalAge()) { static_cast(env->_cycleState)->_vlhgcIncrementStats._copyForwardStats._edenSurvivorRegionCount += 1; } else { diff --git a/runtime/gc_vlhgc/SchedulingDelegate.cpp b/runtime/gc_vlhgc/SchedulingDelegate.cpp index 8a3cf5783b7..28937b74139 100644 --- a/runtime/gc_vlhgc/SchedulingDelegate.cpp +++ b/runtime/gc_vlhgc/SchedulingDelegate.cpp @@ -372,7 +372,15 @@ MM_SchedulingDelegate::partialGarbageCollectCompleted(MM_EnvironmentVLHGC *env, bool globalSweepHappened = _globalSweepRequired; _globalSweepRequired = false; /* copy out the Eden size of the previous interval (between the last PGC and this one) before we recalculate the next one */ - uintptr_t edenCountBeforeCollect = getCurrentEdenSizeInRegions(env); + /* During GC, the heap may expand to allow the current collection to continue. + * A heap resize triggers an eden size recalculation without allowing further + * heap expansion (heap reconfiguration). As a result, the newly calculated + * eden size can differ significantly from the eden size at the start of the + * collection, causing the SurvivalRate calculation to become inaccurate. + * Therefore, set copyForwardStats->_edenEvacuateRegionCount (instead of getCurrentEdenSizeInRegions(env)) to + * edenCountBeforeCollect. + */ + uintptr_t edenCountBeforeCollect = copyForwardStats->_edenEvacuateRegionCount; Trc_MM_SchedulingDelegate_partialGarbageCollectCompleted_stats(env->getLanguageVMThread(), copyForwardStats->_edenEvacuateRegionCount, @@ -393,12 +401,27 @@ MM_SchedulingDelegate::partialGarbageCollectCompleted(MM_EnvironmentVLHGC *env, Assert_MM_true( (0 == copyForwardStats->_scanBytesEden) || copyForwardStats->_aborted || (0 != copyForwardStats->_nonEvacuateRegionCount)); Assert_MM_true( (0 == copyForwardStats->_scanBytesNonEden) || copyForwardStats->_aborted || (0 != copyForwardStats->_nonEvacuateRegionCount)); edenSurvivorCount += (copyForwardStats->_scanBytesEden + regionSize - 1) / regionSize; + Assert_GC_true_with_message(env, copyForwardStats->_edenSurvivorRegionCount <= edenCountBeforeCollect, + "partialGarbageCollectCompleted copyForwardStats->_edenSurvivorRegionCount=%zu, copyForwardStats->_edenEvacuateRegionCount=%zu, edenCountBeforeCollect=%zu, edenSurvivorCount=%zu, copyForwardStats->_aborted=%zu, getCurrentEdenSizeInRegions(env)=%zu\n", + copyForwardStats->_edenSurvivorRegionCount, copyForwardStats->_edenEvacuateRegionCount, edenCountBeforeCollect, edenSurvivorCount, copyForwardStats->_aborted, getCurrentEdenSizeInRegions(env)); + if (edenSurvivorCount > edenCountBeforeCollect) { + /* when abort is in progress, every Eden object scanned in abort-recovery contributes to _scannedBytes. + * But an object that was partially copied before abort (the copy succeeded, + * the forwarding pointer was installed) is also counted again during the abort scan of the source region. + * So _scanBytesEden might be double-counted, then cause edenSurvivorCount is bigger than edenCountBeforeCollect. + * for this case, set edenSurvivorCount = edenCountBeforeCollect. + */ + Assert_MM_true(copyForwardStats->_aborted); + edenSurvivorCount = edenCountBeforeCollect; + } nonEdenSurvivorCount += (copyForwardStats->_scanBytesNonEden + regionSize - 1) / regionSize; /* Eden count could be 0 in special case, after compaction if there is still no free region for scheduling eden(eden count = 0), will skip update Survival Rate */ if (0 != edenCountBeforeCollect) { + /* SurvivalRate should never be over 1.0 */ double thisSurvivalRate = (double)edenSurvivorCount / (double)edenCountBeforeCollect; + Assert_MM_true(1.0 >= thisSurvivalRate); updateSurvivalRatesAfterCopyForward(thisSurvivalRate, nonEdenSurvivorCount); }