RecyclerSweep.h 10 KB

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