@@ -895,6 +895,7 @@ void SatoriRegion::MarkFn(PTR_PTR_Object ppObject, ScanContext* sc, uint32_t fla
895895 if (!region->IsMarked (o))
896896 {
897897 region->SetMarked (o);
898+ region->m_occupancy += o->Size ();
898899 region->PushToMarkStackIfHasPointers (o);
899900 }
900901
@@ -1081,7 +1082,11 @@ void SatoriRegion::EscapeFn(SatoriObject** dst, SatoriObject* src, SatoriRegion*
10811082
10821083bool SatoriRegion::ThreadLocalCollect (size_t allocBytes)
10831084{
1084- // TUNING: 1/4 is not too greedy? maybe 1/8 ?
1085+ if (m_escapedSize > Satori::MAX_ESCAPE_SIZE)
1086+ {
1087+ return false ;
1088+ }
1089+
10851090 if (allocBytes - m_allocBytesAtCollect < Satori::REGION_SIZE_GRANULARITY / 4 )
10861091 {
10871092 // this is too soon. last collection did not buy us as much as we wanted
@@ -1095,17 +1100,26 @@ bool SatoriRegion::ThreadLocalCollect(size_t allocBytes)
10951100 size_t count = Recycler ()->IncrementGen0Count ();
10961101 FIRE_EVENT (GCStart_V2, (int )count, 0 , gc_reason::reason_alloc_soh, gc_etw_type_ngc);
10971102
1098- ThreadLocalMark ();
1099- ThreadLocalPlan ();
1100- ThreadLocalUpdatePointers ();
1101- ThreadLocalCompact ();
1103+ bool shouldCollect = ThreadLocalMark ();
1104+ if (shouldCollect)
1105+ {
1106+ ThreadLocalPlan ();
1107+ ThreadLocalUpdatePointers ();
1108+ ThreadLocalCompact ();
1109+ }
11021110
1103- FIRE_EVENT (GCEnd_V1, (int )count, 0 );
1111+ // schedule pending finalizables if we have them
1112+ // must be after compaction, since pend may escape objects.
1113+ if (HasPendingFinalizables ())
1114+ {
1115+ ThreadLocalPendFinalizables ();
1116+ }
11041117
1105- return true ;
1118+ FIRE_EVENT (GCEnd_V1, (int )count, 0 );
1119+ return shouldCollect;
11061120}
11071121
1108- void SatoriRegion::ThreadLocalMark ()
1122+ bool SatoriRegion::ThreadLocalMark ()
11091123{
11101124 Verify ();
11111125
@@ -1156,6 +1170,18 @@ void SatoriRegion::ThreadLocalMark()
11561170 _ASSERTE (escaped == this ->m_escapedSize );
11571171#endif
11581172
1173+ // We expect high mortality rate of Gen0 objects.
1174+ // If surviving set is large, then collection will be more expensive with diminishing results.
1175+ // We will not continue with collection if we see that too much of thread local objects are alive.
1176+ // The criteria does not need to be very precise. (anything in the order of 1/8 and 1/16 seems
1177+ // to yield similar results)
1178+ const size_t maxSurv = Satori::REGION_SIZE_GRANULARITY / 8 ;
1179+
1180+ // Temporarily use m_occupancy to estimate surviving size.
1181+ // If we proceed with collection, m_occupancy will be recomputed anyways.
1182+ size_t uncollectedOccupancy = m_occupancy;
1183+ m_occupancy = 0 ;
1184+
11591185 // mark roots for the current stack
11601186 ScanContext sc;
11611187 sc.promotion = TRUE ;
@@ -1170,7 +1196,7 @@ void SatoriRegion::ThreadLocalMark()
11701196 SatoriObject* o = PopFromMarkStack ();
11711197
11721198 propagateMarks:
1173- while (o)
1199+ while (o && m_occupancy < maxSurv )
11741200 {
11751201 _ASSERTE (IsMarked (o));
11761202 _ASSERTE (!IsEscaped (o));
@@ -1182,6 +1208,7 @@ void SatoriRegion::ThreadLocalMark()
11821208 if (child->SameRegion (this ) && !IsMarked (child))
11831209 {
11841210 SetMarked (child);
1211+ m_occupancy += child->Size ();
11851212 PushToMarkStackIfHasPointers (child);
11861213 }
11871214 },
@@ -1190,6 +1217,14 @@ void SatoriRegion::ThreadLocalMark()
11901217 o = PopFromMarkStack ();
11911218 }
11921219
1220+ if (m_occupancy >= maxSurv)
1221+ {
1222+ // surviving set is too large.
1223+ while (PopFromMarkStack ()){};
1224+ m_occupancy = uncollectedOccupancy;
1225+ return false ;
1226+ }
1227+
11931228 if (checkFinalizables)
11941229 {
11951230 // unreachable finalizables:
@@ -1217,6 +1252,7 @@ void SatoriRegion::ThreadLocalMark()
12171252 {
12181253 // keep alive
12191254 SetMarked (finalizable);
1255+ m_occupancy += finalizable->Size ();
12201256 PushToMarkStackIfHasPointers (finalizable);
12211257 (size_t &)finalizable |= Satori::FINALIZATION_PENDING;
12221258 HasPendingFinalizables () = true ;
@@ -1236,6 +1272,7 @@ void SatoriRegion::ThreadLocalMark()
12361272 }
12371273
12381274 Verify (/* allowMarked*/ true );
1275+ return true ;
12391276}
12401277
12411278void SatoriRegion::ThreadLocalPlan ()
@@ -1608,13 +1645,6 @@ void SatoriRegion::ThreadLocalCompact()
16081645 }
16091646 }
16101647
1611- // schedule pending finalizables if we have them
1612- // must be after compaction, since pend may escape objects.
1613- if (HasPendingFinalizables ())
1614- {
1615- ThreadLocalPendFinalizables ();
1616- }
1617-
16181648 Verify ();
16191649
16201650 _ASSERTE ((Satori::REGION_SIZE_GRANULARITY - offsetof (SatoriRegion, m_firstObject) - foundFree) == m_occupancy);
0 commit comments