RecyclerSweep.h 9.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. //-------------------------------------------------------------------------------------------------------
  2. // Copyright (C) Microsoft. All rights reserved.
  3. // Licensed under the MIT license. See LICENSE.txt file in the project root for full license information.
  4. //-------------------------------------------------------------------------------------------------------
  5. #pragma once
  6. namespace Memory
  7. {
  8. // RecyclerSweep - Sweeping algorithm and state
  9. class RecyclerSweep
  10. #if DBG
  11. : public RecyclerVerifyListConsistencyData
  12. #endif
  13. {
  14. public:
  15. void BeginSweep(Recycler * recycler, RecyclerSweepManager * recyclerSweepManager, HeapInfo * heapInfo);
  16. void ShutdownCleanup();
  17. Recycler * GetRecycler() const;
  18. RecyclerSweepManager * GetManager() const;
  19. bool IsBackground() const;
  20. void FlushPendingTransferDisposedObjects();
  21. #if ENABLE_CONCURRENT_GC
  22. bool HasPendingSweepSmallHeapBlocks() const;
  23. void SetHasPendingSweepSmallHeapBlocks();
  24. template <typename TBlockType>
  25. TBlockType *& GetPendingSweepBlockList(HeapBucketT<TBlockType> const * heapBucket);
  26. bool HasPendingEmptyBlocks() const;
  27. template <typename TBlockType> void QueueEmptyHeapBlock(HeapBucketT<TBlockType> const *heapBucket, TBlockType * heapBlock);
  28. template <typename TBlockType> void TransferPendingEmptyHeapBlocks(HeapBucketT<TBlockType> * heapBucket);
  29. template <typename TBlockType> void SetPendingMergeNewHeapBlockList(TBlockType * heapBlockList);
  30. template <typename TBlockType> void MergePendingNewHeapBlockList();
  31. template <typename TBlockType> void MergePendingNewMediumHeapBlockList();
  32. #if DBG
  33. bool HasPendingNewHeapBlocks() const;
  34. template <typename TBlockType> TBlockType * GetSavedNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket);
  35. template <typename TBlockType> void SaveNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket);
  36. #endif
  37. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  38. template <typename TBlockType> size_t GetHeapBlockCount(HeapBucketT<TBlockType> const * heapBucket);
  39. size_t GetPendingMergeNewHeapBlockCount(HeapInfo const * heapInfo);
  40. #endif
  41. #endif
  42. #if ENABLE_PARTIAL_GC
  43. bool InPartialCollectMode() const;
  44. bool InPartialCollect() const;
  45. #endif
  46. private:
  47. template <typename TBlockType>
  48. struct BucketData
  49. {
  50. #if ENABLE_PARTIAL_GC || ENABLE_CONCURRENT_GC
  51. TBlockType * pendingSweepList;
  52. TBlockType * pendingFinalizableSweptList;
  53. #endif
  54. #if ENABLE_CONCURRENT_GC
  55. TBlockType * pendingEmptyBlockList;
  56. TBlockType * pendingEmptyBlockListTail;
  57. #if DBG
  58. TBlockType * savedNextAllocableBlockHead;
  59. #endif
  60. #endif
  61. };
  62. template <typename TBlockType>
  63. BucketData<TBlockType>& GetBucketData(HeapBucketT<TBlockType> const * bucket)
  64. {
  65. if (TBlockType::HeapBlockAttributes::IsSmallBlock)
  66. {
  67. return this->GetData<TBlockType>().bucketData[bucket->GetBucketIndex()];
  68. }
  69. else
  70. {
  71. Assert(TBlockType::HeapBlockAttributes::IsMediumBlock);
  72. return this->GetData<TBlockType>().bucketData[bucket->GetMediumBucketIndex()];
  73. }
  74. }
  75. template <typename TBlockType>
  76. struct Data
  77. {
  78. BucketData<TBlockType> bucketData[TBlockType::HeapBlockAttributes::BucketCount];
  79. #if ENABLE_CONCURRENT_GC
  80. TBlockType * pendingMergeNewHeapBlockList;
  81. #endif
  82. };
  83. template <typename TBlockType> Data<TBlockType>& GetData();
  84. template <> Data<SmallLeafHeapBlock>& GetData<SmallLeafHeapBlock>() { return leafData; }
  85. template <> Data<SmallNormalHeapBlock>& GetData<SmallNormalHeapBlock>() { return normalData; }
  86. template <> Data<SmallFinalizableHeapBlock>& GetData<SmallFinalizableHeapBlock>() { return finalizableData; }
  87. #ifdef RECYCLER_VISITED_HOST
  88. template <> Data<SmallRecyclerVisitedHostHeapBlock>& GetData<SmallRecyclerVisitedHostHeapBlock>() { return recyclerVisitedHostData; }
  89. #endif
  90. #ifdef RECYCLER_WRITE_BARRIER
  91. template <> Data<SmallNormalWithBarrierHeapBlock>& GetData<SmallNormalWithBarrierHeapBlock>() { return withBarrierData; }
  92. template <> Data<SmallFinalizableWithBarrierHeapBlock>& GetData<SmallFinalizableWithBarrierHeapBlock>() { return finalizableWithBarrierData; }
  93. #endif
  94. template <> Data<MediumLeafHeapBlock>& GetData<MediumLeafHeapBlock>() { return mediumLeafData; }
  95. template <> Data<MediumNormalHeapBlock>& GetData<MediumNormalHeapBlock>() { return mediumNormalData; }
  96. template <> Data<MediumFinalizableHeapBlock>& GetData<MediumFinalizableHeapBlock>() { return mediumFinalizableData; }
  97. #ifdef RECYCLER_VISITED_HOST
  98. template <> Data<MediumRecyclerVisitedHostHeapBlock>& GetData<MediumRecyclerVisitedHostHeapBlock>() { return mediumRecyclerVisitedHostData; }
  99. #endif
  100. #ifdef RECYCLER_WRITE_BARRIER
  101. template <> Data<MediumNormalWithBarrierHeapBlock>& GetData<MediumNormalWithBarrierHeapBlock>() { return mediumWithBarrierData; }
  102. template <> Data<MediumFinalizableWithBarrierHeapBlock>& GetData<MediumFinalizableWithBarrierHeapBlock>() { return mediumFinalizableWithBarrierData; }
  103. #endif
  104. private:
  105. Recycler * recycler;
  106. RecyclerSweepManager * recyclerSweepManager;
  107. HeapInfo * heapInfo;
  108. Data<SmallLeafHeapBlock> leafData;
  109. Data<SmallNormalHeapBlock> normalData;
  110. Data<SmallFinalizableHeapBlock> finalizableData;
  111. #ifdef RECYCLER_VISITED_HOST
  112. Data<SmallRecyclerVisitedHostHeapBlock> recyclerVisitedHostData;
  113. #endif
  114. #ifdef RECYCLER_WRITE_BARRIER
  115. Data<SmallNormalWithBarrierHeapBlock> withBarrierData;
  116. Data<SmallFinalizableWithBarrierHeapBlock> finalizableWithBarrierData;
  117. #endif
  118. Data<MediumLeafHeapBlock> mediumLeafData;
  119. Data<MediumNormalHeapBlock> mediumNormalData;
  120. Data<MediumFinalizableHeapBlock> mediumFinalizableData;
  121. #ifdef RECYCLER_VISITED_HOST
  122. Data<MediumRecyclerVisitedHostHeapBlock> mediumRecyclerVisitedHostData;
  123. #endif
  124. #ifdef RECYCLER_WRITE_BARRIER
  125. Data<MediumNormalWithBarrierHeapBlock> mediumWithBarrierData;
  126. Data<MediumFinalizableWithBarrierHeapBlock> mediumFinalizableWithBarrierData;
  127. #endif
  128. bool hasPendingSweepSmallHeapBlocks;
  129. bool hasPendingEmptyBlocks;
  130. };
  131. #if ENABLE_CONCURRENT_GC
  132. template <typename TBlockType>
  133. TBlockType *&
  134. RecyclerSweep::GetPendingSweepBlockList(HeapBucketT<TBlockType> const * heapBucket)
  135. {
  136. return this->GetBucketData<TBlockType>(heapBucket).pendingSweepList;
  137. }
  138. #endif
  139. #if ENABLE_CONCURRENT_GC
  140. template <typename TBlockType>
  141. void
  142. RecyclerSweep::QueueEmptyHeapBlock(HeapBucketT<TBlockType> const *heapBucket, TBlockType * heapBlock)
  143. {
  144. #if ENABLE_BACKGROUND_PAGE_FREEING
  145. if (CONFIG_FLAG(EnableBGFreeZero))
  146. {
  147. auto& bucketData = this->GetBucketData(heapBucket);
  148. Assert(heapBlock->heapBucket == heapBucket);
  149. heapBlock->BackgroundReleasePagesSweep(recycler);
  150. TBlockType * list = bucketData.pendingEmptyBlockList;
  151. if (list == nullptr)
  152. {
  153. Assert(bucketData.pendingEmptyBlockListTail == nullptr);
  154. bucketData.pendingEmptyBlockListTail = heapBlock;
  155. this->hasPendingEmptyBlocks = true;
  156. }
  157. heapBlock->SetNextBlock(list);
  158. bucketData.pendingEmptyBlockList = heapBlock;
  159. }
  160. #endif
  161. }
  162. template <typename TBlockType>
  163. void
  164. RecyclerSweep::TransferPendingEmptyHeapBlocks(HeapBucketT<TBlockType> * heapBucket)
  165. {
  166. Assert(!this->IsBackground());
  167. Assert(!heapBucket->IsAllocationStopped());
  168. RECYCLER_SLOW_CHECK(heapBucket->VerifyHeapBlockCount(false));
  169. auto& bucketData = this->GetBucketData(heapBucket);
  170. Assert(bucketData.pendingSweepList == nullptr);
  171. TBlockType * list = bucketData.pendingEmptyBlockList;
  172. if (list)
  173. {
  174. TBlockType * tail = bucketData.pendingEmptyBlockListTail;
  175. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED) || ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  176. uint32 count = 0;
  177. HeapBlockList::ForEach(list, [tail, &count](TBlockType * heapBlock)
  178. {
  179. Assert(heapBlock->GetAddress() == nullptr);
  180. Assert(heapBlock->GetSegment() == nullptr);
  181. Assert(heapBlock->GetNextBlock() != nullptr || heapBlock == tail);
  182. count++;
  183. });
  184. #if defined(RECYCLER_SLOW_CHECK_ENABLED)
  185. heapBucket->emptyHeapBlockCount += count;
  186. #endif
  187. #if defined(RECYCLER_SLOW_CHECK_ENABLED) || ENABLE_ALLOCATIONS_DURING_CONCURRENT_SWEEP
  188. heapBucket->heapBlockCount -= count;
  189. #endif
  190. #endif
  191. tail->SetNextBlock(heapBucket->emptyBlockList);
  192. heapBucket->emptyBlockList = list;
  193. bucketData.pendingEmptyBlockList = nullptr;
  194. RECYCLER_SLOW_CHECK(heapBucket->VerifyHeapBlockCount(false));
  195. }
  196. else
  197. {
  198. Assert(bucketData.pendingEmptyBlockListTail == nullptr);
  199. }
  200. }
  201. template <typename TBlockType>
  202. void
  203. RecyclerSweep::SetPendingMergeNewHeapBlockList(TBlockType * heapBlockList)
  204. {
  205. this->GetData<TBlockType>().pendingMergeNewHeapBlockList = heapBlockList;
  206. }
  207. #if DBG
  208. template <typename TBlockType>
  209. TBlockType *
  210. RecyclerSweep::GetSavedNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket)
  211. {
  212. return this->GetBucketData(heapBucket).savedNextAllocableBlockHead;
  213. }
  214. template <typename TBlockType>
  215. void
  216. RecyclerSweep::SaveNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket)
  217. {
  218. this->GetBucketData(heapBucket).savedNextAllocableBlockHead = heapBucket->nextAllocableBlockHead;
  219. }
  220. #endif
  221. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  222. template <typename TBlockType>
  223. size_t
  224. RecyclerSweep::GetHeapBlockCount(HeapBucketT<TBlockType> const * heapBucket)
  225. {
  226. if (heapBucket->heapInfo != this->heapInfo)
  227. {
  228. return 0;
  229. }
  230. auto& bucketData = this->GetBucketData(heapBucket);
  231. return HeapBlockList::Count(bucketData.pendingSweepList)
  232. + HeapBlockList::Count(bucketData.pendingEmptyBlockList);
  233. }
  234. #endif
  235. #endif
  236. }