RecyclerSweep.h 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292
  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. #if ENABLE_PARTIAL_GC
  16. void BeginSweep(Recycler * recycler, size_t rescanRootBytes, bool adjustPartialHeuristics);
  17. #else
  18. void BeginSweep(Recycler * recycler);
  19. #endif
  20. void FinishSweep();
  21. void EndSweep();
  22. void ShutdownCleanup();
  23. Recycler * GetRecycler() const;
  24. bool IsBackground() const;
  25. bool HasSetupBackgroundSweep() const;
  26. void FlushPendingTransferDisposedObjects();
  27. #if ENABLE_CONCURRENT_GC
  28. bool HasPendingSweepSmallHeapBlocks() const;
  29. void SetHasPendingSweepSmallHeapBlocks();
  30. template <typename TBlockType>
  31. TBlockType *& GetPendingSweepBlockList(HeapBucketT<TBlockType> const * heapBucket);
  32. bool HasPendingEmptyBlocks() const;
  33. template <typename TBlockType> void QueueEmptyHeapBlock(HeapBucketT<TBlockType> const *heapBucket, TBlockType * heapBlock);
  34. template <typename TBlockType> void TransferPendingEmptyHeapBlocks(HeapBucketT<TBlockType> * heapBucket);
  35. void BackgroundSweep();
  36. void BeginBackground(bool forceForeground);
  37. void EndBackground();
  38. template <typename TBlockType> void SetPendingMergeNewHeapBlockList(TBlockType * heapBlockList);
  39. template <typename TBlockType> void MergePendingNewHeapBlockList();
  40. template <typename TBlockType> void MergePendingNewMediumHeapBlockList();
  41. #if DBG
  42. bool HasPendingNewHeapBlocks() const;
  43. template <typename TBlockType> TBlockType * GetSavedNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket);
  44. template <typename TBlockType> void SaveNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket);
  45. #endif
  46. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  47. template < typename TBlockType> size_t GetHeapBlockCount(HeapBucketT<TBlockType> const * heapBucket);
  48. size_t SetPendingMergeNewHeapBlockCount();
  49. #endif
  50. #endif
  51. template <typename TBlockAttributes>
  52. void AddUnaccountedNewObjectAllocBytes(SmallHeapBlockT<TBlockAttributes> * smallHeapBlock);
  53. #if ENABLE_PARTIAL_GC
  54. bool InPartialCollectMode() const;
  55. bool InPartialCollect() const;
  56. void StartPartialCollectMode();
  57. bool DoPartialCollectMode();
  58. bool DoAdjustPartialHeuristics() const;
  59. bool AdjustPartialHeuristics();
  60. void SubtractSweepNewObjectAllocBytes(size_t newObjectExpectSweepByteCount);
  61. size_t GetNewObjectAllocBytes() const;
  62. size_t GetNewObjectFreeBytes() const;
  63. size_t GetPartialUnusedFreeByteCount() const;
  64. size_t GetPartialCollectSmallHeapBlockReuseMinFreeBytes() const;
  65. template <typename TBlockAttributes>
  66. void NotifyAllocableObjects(SmallHeapBlockT<TBlockAttributes> * smallHeapBlock);
  67. void AddUnusedFreeByteCount(uint expectedFreeByteCount);
  68. static const uint MinPartialUncollectedNewPageCount; // 4MB pages
  69. static const uint MaxPartialCollectRescanRootBytes; // 5MB
  70. #endif
  71. private:
  72. template <typename TBlockType>
  73. struct BucketData
  74. {
  75. #if ENABLE_PARTIAL_GC || ENABLE_CONCURRENT_GC
  76. TBlockType * pendingSweepList;
  77. TBlockType * pendingFinalizableSweptList;
  78. #endif
  79. #if ENABLE_CONCURRENT_GC
  80. TBlockType * pendingEmptyBlockList;
  81. TBlockType * pendingEmptyBlockListTail;
  82. #if DBG
  83. TBlockType * savedNextAllocableBlockHead;
  84. #endif
  85. #endif
  86. };
  87. template <typename TBlockType>
  88. BucketData<TBlockType>& GetBucketData(HeapBucketT<TBlockType> const * bucket)
  89. {
  90. if (TBlockType::HeapBlockAttributes::IsSmallBlock)
  91. {
  92. return this->GetData<TBlockType>().bucketData[bucket->GetBucketIndex()];
  93. }
  94. else
  95. {
  96. Assert(TBlockType::HeapBlockAttributes::IsMediumBlock);
  97. return this->GetData<TBlockType>().bucketData[bucket->GetMediumBucketIndex()];
  98. }
  99. }
  100. template <typename TBlockType>
  101. struct Data
  102. {
  103. BucketData<TBlockType> bucketData[TBlockType::HeapBlockAttributes::BucketCount];
  104. #if ENABLE_CONCURRENT_GC
  105. TBlockType * pendingMergeNewHeapBlockList;
  106. #endif
  107. };
  108. template <typename TBlockType> Data<TBlockType>& GetData();
  109. template <> Data<SmallLeafHeapBlock>& GetData<SmallLeafHeapBlock>() { return leafData; }
  110. template <> Data<SmallNormalHeapBlock>& GetData<SmallNormalHeapBlock>() { return normalData; }
  111. template <> Data<SmallFinalizableHeapBlock>& GetData<SmallFinalizableHeapBlock>() { return finalizableData; }
  112. #ifdef RECYCLER_WRITE_BARRIER
  113. template <> Data<SmallNormalWithBarrierHeapBlock>& GetData<SmallNormalWithBarrierHeapBlock>() { return withBarrierData; }
  114. template <> Data<SmallFinalizableWithBarrierHeapBlock>& GetData<SmallFinalizableWithBarrierHeapBlock>() { return finalizableWithBarrierData; }
  115. #endif
  116. template <> Data<MediumLeafHeapBlock>& GetData<MediumLeafHeapBlock>() { return mediumLeafData; }
  117. template <> Data<MediumNormalHeapBlock>& GetData<MediumNormalHeapBlock>() { return mediumNormalData; }
  118. template <> Data<MediumFinalizableHeapBlock>& GetData<MediumFinalizableHeapBlock>() { return mediumFinalizableData; }
  119. #ifdef RECYCLER_WRITE_BARRIER
  120. template <> Data<MediumNormalWithBarrierHeapBlock>& GetData<MediumNormalWithBarrierHeapBlock>() { return mediumWithBarrierData; }
  121. template <> Data<MediumFinalizableWithBarrierHeapBlock>& GetData<MediumFinalizableWithBarrierHeapBlock>() { return mediumFinalizableWithBarrierData; }
  122. #endif
  123. private:
  124. bool IsMemProtectMode();
  125. Recycler * recycler;
  126. Data<SmallLeafHeapBlock> leafData;
  127. Data<SmallNormalHeapBlock> normalData;
  128. Data<SmallFinalizableHeapBlock> finalizableData;
  129. #ifdef RECYCLER_WRITE_BARRIER
  130. Data<SmallNormalWithBarrierHeapBlock> withBarrierData;
  131. Data<SmallFinalizableWithBarrierHeapBlock> finalizableWithBarrierData;
  132. #endif
  133. Data<MediumLeafHeapBlock> mediumLeafData;
  134. Data<MediumNormalHeapBlock> mediumNormalData;
  135. Data<MediumFinalizableHeapBlock> mediumFinalizableData;
  136. #ifdef RECYCLER_WRITE_BARRIER
  137. Data<MediumNormalWithBarrierHeapBlock> mediumWithBarrierData;
  138. Data<MediumFinalizableWithBarrierHeapBlock> mediumFinalizableWithBarrierData;
  139. #endif
  140. bool background;
  141. bool forceForeground;
  142. bool hasPendingSweepSmallHeapBlocks;
  143. bool hasPendingEmptyBlocks;
  144. bool inPartialCollect;
  145. #if ENABLE_PARTIAL_GC
  146. bool adjustPartialHeuristics;
  147. size_t lastPartialUncollectedAllocBytes;
  148. size_t nextPartialUncollectedAllocBytes;
  149. // Sweep data for partial activation heuristic
  150. size_t rescanRootBytes;
  151. size_t reuseHeapBlockCount;
  152. size_t reuseByteCount;
  153. // Partial reuse Heuristic
  154. size_t partialCollectSmallHeapBlockReuseMinFreeBytes;
  155. // Data to update unusedPartialCollectFreeBytes
  156. size_t partialUnusedFreeByteCount;
  157. #if DBG
  158. bool partial;
  159. #endif
  160. #endif
  161. };
  162. #if ENABLE_CONCURRENT_GC
  163. template <typename TBlockType>
  164. TBlockType *&
  165. RecyclerSweep::GetPendingSweepBlockList(HeapBucketT<TBlockType> const * heapBucket)
  166. {
  167. return this->GetBucketData<TBlockType>(heapBucket).pendingSweepList;
  168. }
  169. #endif
  170. #if ENABLE_CONCURRENT_GC
  171. template <typename TBlockType>
  172. void
  173. RecyclerSweep::QueueEmptyHeapBlock(HeapBucketT<TBlockType> const *heapBucket, TBlockType * heapBlock)
  174. {
  175. #if ENABLE_BACKGROUND_PAGE_FREEING
  176. if (CONFIG_FLAG(EnableBGFreeZero))
  177. {
  178. auto& bucketData = this->GetBucketData(heapBucket);
  179. Assert(heapBlock->heapBucket == heapBucket);
  180. heapBlock->BackgroundReleasePagesSweep(recycler);
  181. TBlockType * list = bucketData.pendingEmptyBlockList;
  182. if (list == nullptr)
  183. {
  184. Assert(bucketData.pendingEmptyBlockListTail == nullptr);
  185. bucketData.pendingEmptyBlockListTail = heapBlock;
  186. this->hasPendingEmptyBlocks = true;
  187. }
  188. heapBlock->SetNextBlock(list);
  189. bucketData.pendingEmptyBlockList = heapBlock;
  190. }
  191. #endif
  192. }
  193. template <typename TBlockType>
  194. void
  195. RecyclerSweep::TransferPendingEmptyHeapBlocks(HeapBucketT<TBlockType> * heapBucket)
  196. {
  197. Assert(!this->IsBackground());
  198. Assert(!heapBucket->IsAllocationStopped());
  199. RECYCLER_SLOW_CHECK(heapBucket->VerifyHeapBlockCount(false));
  200. auto& bucketData = this->GetBucketData(heapBucket);
  201. Assert(bucketData.pendingSweepList == nullptr);
  202. TBlockType * list = bucketData.pendingEmptyBlockList;
  203. if (list)
  204. {
  205. TBlockType * tail = bucketData.pendingEmptyBlockListTail;
  206. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  207. size_t count = 0;
  208. HeapBlockList::ForEach(list, [tail, &count](TBlockType * heapBlock)
  209. {
  210. Assert(heapBlock->GetAddress() == nullptr);
  211. Assert(heapBlock->GetSegment() == nullptr);
  212. Assert(heapBlock->GetNextBlock() != nullptr || heapBlock == tail);
  213. count++;
  214. });
  215. RECYCLER_SLOW_CHECK(heapBucket->emptyHeapBlockCount += count);
  216. RECYCLER_SLOW_CHECK(heapBucket->heapBlockCount -= count);
  217. #endif
  218. tail->SetNextBlock(heapBucket->emptyBlockList);
  219. heapBucket->emptyBlockList = list;
  220. bucketData.pendingEmptyBlockList = nullptr;
  221. RECYCLER_SLOW_CHECK(heapBucket->VerifyHeapBlockCount(false));
  222. }
  223. else
  224. {
  225. Assert(bucketData.pendingEmptyBlockListTail == nullptr);
  226. }
  227. }
  228. template <typename TBlockType>
  229. void
  230. RecyclerSweep::SetPendingMergeNewHeapBlockList(TBlockType * heapBlockList)
  231. {
  232. this->GetData<TBlockType>().pendingMergeNewHeapBlockList = heapBlockList;
  233. }
  234. #if DBG
  235. template <typename TBlockType>
  236. TBlockType *
  237. RecyclerSweep::GetSavedNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket)
  238. {
  239. return this->GetBucketData(heapBucket).savedNextAllocableBlockHead;
  240. }
  241. template <typename TBlockType>
  242. void
  243. RecyclerSweep::SaveNextAllocableBlockHead(HeapBucketT<TBlockType> const * heapBucket)
  244. {
  245. this->GetBucketData(heapBucket).savedNextAllocableBlockHead = heapBucket->nextAllocableBlockHead;
  246. }
  247. #endif
  248. #if DBG || defined(RECYCLER_SLOW_CHECK_ENABLED)
  249. template < typename TBlockType>
  250. size_t
  251. RecyclerSweep::GetHeapBlockCount(HeapBucketT<TBlockType> const * heapBucket)
  252. {
  253. auto& bucketData = this->GetBucketData(heapBucket);
  254. return HeapBlockList::Count(bucketData.pendingSweepList)
  255. + HeapBlockList::Count(bucketData.pendingEmptyBlockList);
  256. }
  257. #endif
  258. #endif
  259. }