void SmallNormalHeapBucketBase<TBlockType>::SweepPartialReusePages(RecyclerSweep& recyclerSweep) { RECYCLER_SLOW_CHECK(this->VerifyHeapBlockCount(recyclerSweep.IsBackground())); Assert(this->GetRecycler()->inPartialCollectMode); TBlockType * currentHeapBlockList = this->heapBlockList; this->heapBlockList = nullptr; SmallNormalHeapBucketBase<TBlockType>::SweepPartialReusePages(recyclerSweep, currentHeapBlockList, this->heapBlockList, this->partialHeapBlockList, [](TBlockType * heapBlock, bool isReused) {}); #if ENABLE_CONCURRENT_GC // only collect data for pending sweep list but don't sweep yet // until we have adjusted the heuristics, and SweepPartialReusePages will // sweep the page that we are going to reuse in thread. TBlockType *& pendingSweepList = recyclerSweep.GetPendingSweepBlockList(this); currentHeapBlockList = pendingSweepList; pendingSweepList = nullptr; Recycler * recycler = recyclerSweep.GetRecycler(); SmallNormalHeapBucketBase<TBlockType>::SweepPartialReusePages(recyclerSweep, currentHeapBlockList, this->heapBlockList, pendingSweepList, [recycler](TBlockType * heapBlock, bool isReused) { if (isReused) { // Finalizable blocks are always swept in thread, so shouldn't be here Assert(!heapBlock->IsAnyFinalizableBlock()); // Page heap blocks are never swept concurrently heapBlock->template SweepObjects<SweepMode_InThread>(recycler); // This block has been counted as concurrently swept, and now we changed our mind // and sweep it in thread. Remove the count RECYCLER_STATS_DEC(recycler, heapBlockConcurrentSweptCount[heapBlock->GetHeapBlockType()]); } } ); #endif RECYCLER_SLOW_CHECK(this->VerifyHeapBlockCount(recyclerSweep.IsBackground())); this->StartAllocationAfterSweep(); // PARTIALGC-TODO: revisit partial heap blocks to see if they can be put back into use // since the heuristics limit may be been changed. }
void SmallNormalHeapBucketBase<TBlockType>::SweepPendingObjects(RecyclerSweep& recyclerSweep) { RECYCLER_SLOW_CHECK(VerifyHeapBlockCount(recyclerSweep.IsBackground())); CompileAssert(!BaseT::IsLeafBucket); TBlockType *& pendingSweepList = recyclerSweep.GetPendingSweepBlockList(this); TBlockType * const list = pendingSweepList; Recycler * const recycler = recyclerSweep.GetRecycler(); #if ENABLE_PARTIAL_GC bool const partialSweep = recycler->inPartialCollectMode; #endif if (list) { pendingSweepList = nullptr; #if ENABLE_PARTIAL_GC if (partialSweep) { // We did a partial sweep. // Blocks in the pendingSweepList are the ones we decided not to reuse. HeapBlockList::ForEachEditing(list, [this, recycler](TBlockType * heapBlock) { // We are not going to reuse this block. // SweepMode_ConcurrentPartial will not actually collect anything, it will just update some state. // The sweepable objects will be collected in a future Sweep. // Note, page heap blocks are never swept concurrently heapBlock->template SweepObjects<SweepMode_ConcurrentPartial>(recycler); // page heap mode should never reach here, so don't check pageheap enabled or not if (heapBlock->template HasFreeObject<false>()) { // We have pre-existing free objects, so put this in the partialSweptHeapBlockList heapBlock->SetNextBlock(this->partialSweptHeapBlockList); this->partialSweptHeapBlockList = heapBlock; } else { // No free objects, so put in the fullBlockList heapBlock->SetNextBlock(this->fullBlockList); this->fullBlockList = heapBlock; } }); } else #endif { // We decided not to do a partial sweep. // Blocks in the pendingSweepList need to have a regular sweep. TBlockType * tail = SweepPendingObjects<SweepMode_Concurrent>(recycler, list); tail->SetNextBlock(this->heapBlockList); this->heapBlockList = list; this->StartAllocationAfterSweep(); } RECYCLER_SLOW_CHECK(VerifyHeapBlockCount(recyclerSweep.IsBackground())); } Assert(!this->IsAllocationStopped()); }