1 /** 2 * Copyright (c) 2021-2022 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef PANDA_RUNTIME_MEM_HEAP_SPACE_H 17 #define PANDA_RUNTIME_MEM_HEAP_SPACE_H 18 19 #include "libpandabase/mem/mem_pool.h" 20 #include "libpandabase/os/mutex.h" 21 #include "libpandabase/macros.h" 22 23 #include <optional> 24 25 namespace panda::mem { 26 27 namespace test { 28 class HeapSpaceTest; 29 class MemStatsGenGCTest; 30 template <typename ObjectAllocator, bool REGULAR_SPACE> 31 class RegionAllocatorTestBase; 32 class RegionAllocatorTest; 33 class RegionNonmovableObjectAllocatorTest; 34 class RegionGarbageChoosingTest; 35 class RemSetTest; 36 } // namespace test 37 38 // Object allocation flow: 39 // --------+ 40 // +------+ +-----------+ +------------+ | 41 // | GC | <----+ | Runtime | ... | Compiler | | 42 // +------+ | +-----------+ | +------------+ | 43 // | | +---+ | | 44 // +-----+ | | +---------+ | Standard flow for object allocation 45 // | | | | | 46 // v v v v | 47 // +-------------------+ | 48 // | ObjectAllocator | | 49 // +-------------------+ --------+ 50 // ^ | 51 // | | (if need new pool) 52 // +--------------------+ | 53 // | v 54 // | if need trigger GC +-------------+ 55 // + <------------------| HeapSpace | <---- Here we compute heap limits after GC and make the allocation decision 56 // | NULLPOOL +-------------+ 57 // | | (if can alloc) 58 // | v 59 // | Pool +-------------+ 60 // +---------<----------| PoolManager | 61 // +-------------+ 62 /** 63 * @brief Class for description of object spaces and limits (minimum, maximum, current sizes). 64 * Pools for object spaces is allocated via this class. Also this class cooperate with PoolManager for info getting 65 * about object heap. 66 * Class is some virtual layer between PoolManager and Object allocators and GC for object pools allocations. 67 * HeapSpace is used for non-generational-based GC and as base class for GenerationalSpaces class 68 */ 69 class HeapSpace { 70 public: 71 explicit HeapSpace() = default; 72 NO_COPY_SEMANTIC(HeapSpace); 73 NO_MOVE_SEMANTIC(HeapSpace); 74 virtual ~HeapSpace() = default; 75 76 /** 77 * @brief Heap space inilialization 78 * @param initial_size initial (also minimum) heap space size 79 * @param max_size maximum heap space size 80 * @param min_free_percentage minimum possible percentage of free memory in this heap space, use for heap increasing 81 * computation 82 * @param max_free_percentage maximum possible percentage of free memory in this heap space, use for heap reducing 83 * computation 84 */ 85 void Initialize(size_t initialSize, size_t maxSize, uint32_t minFreePercentage, uint32_t maxFreePercentage); 86 87 /// @brief Compute new size of heap space 88 virtual void ComputeNewSize(); 89 90 /// @brief Get current used heap size 91 virtual size_t GetHeapSize() const; 92 93 /// @brief Try to allocate pool via PoolManager 94 [[nodiscard]] virtual Pool TryAllocPool(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 95 void *allocatorPtr); 96 97 /// @brief Try to allocate arena via PoolManager 98 [[nodiscard]] virtual Arena *TryAllocArena(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType, 99 void *allocatorPtr); 100 101 /// @brief Free pool via PoolManager 102 void FreePool(void *poolMem, size_t poolSize, bool releasePages = true); 103 104 /// @brief Free arena via PoolManager 105 void FreeArena(Arena *arena); 106 GetMinFreePercentage()107 double GetMinFreePercentage() const 108 { 109 return minFreePercentage_; 110 } 111 GetMaxFreePercentage()112 double GetMaxFreePercentage() const 113 { 114 return maxFreePercentage_; 115 } 116 SetIsWorkGC(bool value)117 void SetIsWorkGC(bool value) 118 { 119 isWorkGc_ = value; 120 } 121 122 /// Clamp current maximum heap size as maximum possible heap size 123 void ClampCurrentMaxHeapSize(); 124 125 protected: 126 class ObjectMemorySpace { 127 public: 128 explicit ObjectMemorySpace() = default; 129 DEFAULT_COPY_SEMANTIC(ObjectMemorySpace); 130 DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ObjectMemorySpace); 131 ~ObjectMemorySpace() = default; 132 133 void Initialize(size_t initialSize, size_t maxSize); 134 GetCurrentSize()135 size_t GetCurrentSize() const 136 { 137 return currentSize_; 138 } 139 GetMaxSize()140 size_t GetMaxSize() const 141 { 142 return maxSize_; 143 } 144 GetMinSize()145 size_t GetMinSize() const 146 { 147 return minSize_; 148 } 149 150 void ClampNewMaxSize(size_t newMaxSize); 151 GetCurrentNonOccupiedSize()152 size_t GetCurrentNonOccupiedSize() const 153 { 154 return maxSize_ - currentSize_; 155 } 156 UseFullSpace()157 void UseFullSpace() 158 { 159 currentSize_ = maxSize_; 160 } 161 162 /// @brief Compute new size of heap space 163 void ComputeNewSize(size_t freeBytes, double minFreePercentage, double maxFreePercentage); 164 165 /** 166 * @brief Increase current heap space 167 * @param bytes bytes count for heap space increasing 168 */ 169 void IncreaseBy(uint64_t bytes); 170 171 /** 172 * @brief Reduce current heap space 173 * @param bytes bytes count for heap space reducing 174 */ 175 void ReduceBy(size_t bytes); 176 177 // If we have too big pool for allocation then after space increasing we can have not memory for this pool, 178 // so we save pool size and increase heap space to allocate such pool 179 size_t savedPoolSize {0}; // NOLINT(misc-non-private-member-variables-in-classes) 180 181 private: 182 // min_size_ <= current_size_ <= max_size_ 183 size_t currentSize_ {0}; 184 size_t minSize_ {0}; 185 size_t maxSize_ {0}; 186 }; 187 188 // For avoid zero division 189 static constexpr uint32_t MAX_FREE_PERCENTAGE = 99; 190 191 void InitializePercentages(uint32_t minFreePercentage, uint32_t maxFreePercentage); 192 193 [[nodiscard]] Pool TryAllocPoolBase(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 194 void *allocatorPtr, size_t currentFreeBytesInSpace, ObjectMemorySpace *memSpace, 195 OSPagesAllocPolicy allocPolicy = OSPagesAllocPolicy::NO_POLICY); 196 197 [[nodiscard]] Arena *TryAllocArenaBase(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType, 198 void *allocatorPtr, size_t currentFreeBytesInSpace, 199 ObjectMemorySpace *memSpace); 200 201 /** 202 * @brief Check that we can to allocate requested size into target space 203 * 204 * @param pool_size size of memory chunk for allocation 205 * @param current_free_bytes_in_space current freebytes count into target space 206 * @param mem_space target space in which there will be allocation 207 * 208 * @return std::optional value. If result has value then it contains bytes count for heap increasing (need during 209 * GC, for example), else need to trigger GC 210 */ 211 std::optional<size_t> WillAlloc(size_t poolSize, size_t currentFreeBytesInSpace, 212 const ObjectMemorySpace *memSpace) const; 213 214 /// @return current maximum size of this heap space 215 size_t GetCurrentSize() const; 216 217 /// @return free bytes count for current heap space size 218 size_t GetCurrentFreeBytes(size_t bytesNotInThisSpace = 0) const; 219 IsWorkGC()220 inline bool IsWorkGC() const 221 { 222 return isWorkGc_; 223 } 224 225 mutable os::memory::RWLock heapLock_; // NOLINT(misc-non-private-member-variables-in-classes) 226 ObjectMemorySpace memSpace_; // NOLINT(misc-non-private-member-variables-in-classes) 227 bool isInitialized_ {false}; // NOLINT(misc-non-private-member-variables-in-classes) 228 229 private: 230 // if GC wants allocate memory, but we have not needed memory for this then we increase current heap space 231 bool isWorkGc_ {false}; 232 double minFreePercentage_ {0}; 233 double maxFreePercentage_ {0}; 234 235 friend class panda::mem::test::RegionGarbageChoosingTest; 236 template <typename ObjectAllocator, bool REGULAR_SPACE> 237 friend class panda::mem::test::RegionAllocatorTestBase; 238 friend class panda::mem::test::RegionAllocatorTest; 239 friend class panda::mem::test::RegionNonmovableObjectAllocatorTest; 240 friend class panda::mem::test::RemSetTest; 241 friend class panda::mem::test::HeapSpaceTest; 242 }; 243 244 // Y - memory chunk is used for objects in young space 245 // T - memory chunk is used for objects in tenured space 246 // F - memory chunk which is not used for any space 247 // 248 // +---------------------------------------------------------------------------------------------------------+ 249 // | Real object memory chunks location allocating via PoolManager | 250 // |---------------------------------------------------------------------------------------------------------| 251 // | shared pool (use for G1-GC) young, tenured and free pools | 252 // |-----------------------------|---------------------------------------------------------------------------| 253 // |~~~| | |~~~|~~~| |~~~~~| |~~~~~~~~~| |~~~~~~~~~~~~~| | 254 // |~~~| | |~~~|~~~| |~~~~~| F |~~~~~~~~~| F |~~~~~~~~~~~~~| | 255 // |~Y~| F | F |~Y~|~T~| F |~~Y~~| (free |~~~~T~~~~| (free |~~~~~~T~~~~~~| non-occupied memory (F) | 256 // |~~~| | |~~~|~~~| |~~~~~| pool |~~~~~~~~~| pool |~~~~~~~~~~~~~| | 257 // |~~~| | |~~~|~~~| |~~~~~| map) |~~~~~~~~~| map) |~~~~~~~~~~~~~| | 258 // +---------------------------------------------------------------------------------------------------------+ 259 // ^ | | | | | | ^ ^ 260 // | | | | | | +----------+ | | 261 // | | +-----------+ | | | | | | 262 // | | | +----------|----------+ +--------------+ | all occupied memory via PoolManager | 263 // | | | | +-------+ | +------------+ | 264 // | | | | | | | | 265 // v v v v v v v v 266 // +---------------------------|-----------------------------------------------------------------------------+ 267 // |~~~|~~~|~~~~~| | |~~~|~~~~~~~|~~~~~~~~~~~~~| | | 268 // |~~~|~~~|~~~~~| | |~~~|~~~~~~~|~~~~~~~~~~~~~| | | 269 // |~Y~|~Y~|~~Y~~| F | F |~T~|~~~T~~~|~~~~~~T~~~~~~| F | F | 270 // |~~~|~~~|~~~~~| | |~~~|~~~~~~~|~~~~~~~~~~~~~| | | 271 // |~~~|~~~|~~~~~| | |~~~|~~~~~~~|~~~~~~~~~~~~~| | | 272 // |-------------|-----|-------|-------------------------|-------------------------|-------------------------| 273 // | used | | | used | | | 274 // |-------------------|-------|---------------------------------------------------|-------------------------| 275 // | current max size | | current max size | | 276 // |---------------------------|-----------------------------------------------------------------------------| 277 // | Young space | Tenured space | 278 // |---------------------------|-----------------------------------------------------------------------------| 279 // | young-space-size object-memory-pool 280 // | argument argument 281 // |---------------------------------------------------------------------------------------------------------| 282 // | Generations memory representation | 283 // +---------------------------------------------------------------------------------------------------------+ 284 // 285 // init-young-space-size argument set minimum (initial) current max size for Young space 286 // init-object-memory-pool argument set minimum (initial) current max size for heap 287 /** 288 * Class for description of object spaces and limits (minimum, maximum, current sizes) for generatinal-based GC. 289 * Pools for young and tenured spaces is allocated via this class. Also this class cooperate with PoolManager for info 290 * getting about object spaces. If current max size is not enough for new pool in some space then need to trigger GC 291 */ 292 class GenerationalSpaces final : public HeapSpace { 293 public: 294 explicit GenerationalSpaces() = default; 295 NO_COPY_SEMANTIC(GenerationalSpaces); 296 NO_MOVE_SEMANTIC(GenerationalSpaces); 297 ~GenerationalSpaces() override = default; 298 299 void Initialize(size_t initialYoungSize, bool wasSetInitialYoungSize, size_t maxYoungSize, bool wasSetMaxYoungSize, 300 size_t initialTotalSize, size_t maxTotalSize, uint32_t minFreePercentage, 301 uint32_t maxFreePercentage); 302 303 /// @brief Compute new sizes for young and tenured spaces 304 void ComputeNewSize() override; 305 306 void UpdateSize(size_t desiredYoungSize); 307 308 size_t GetHeapSize() const override; 309 310 // Use for CanAllocInSpace 311 static constexpr bool IS_YOUNG_SPACE = true; 312 static constexpr bool IS_TENURED_SPACE = false; 313 314 /** 315 * @return true if we can allocate requested size in space 316 * 317 * @param is_young young or tenured space 318 * @param chunk_size memory size for allocating in space 319 */ 320 bool CanAllocInSpace(bool isYoung, size_t chunkSize) const; 321 322 size_t GetCurrentYoungSize() const; 323 324 size_t GetMaxYoungSize() const; 325 326 void UseFullYoungSpace(); 327 328 /// @brief Allocate alone young pool (use for Gen-GC) with maximum possible size of young space 329 [[nodiscard]] Pool AllocAlonePoolForYoung(SpaceType spaceType, AllocatorType allocatorType, void *allocatorPtr); 330 331 /** 332 * @brief Try allocate pool for young space (use for G1-GC). 333 * If free size in young space less requested pool size then pool can be allocate only during GC work 334 */ 335 [[nodiscard]] Pool TryAllocPoolForYoung(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 336 void *allocatorPtr); 337 338 /** 339 * @brief Try allocate pool for tenured space (use for generational-based GC). 340 * If free size in tenured space less requested pool size then pool can be allocate only during GC work 341 */ 342 [[nodiscard]] Pool TryAllocPoolForTenured(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 343 void *allocatorPtr, 344 OSPagesAllocPolicy allocPolicy = OSPagesAllocPolicy::NO_POLICY); 345 346 [[nodiscard]] Pool TryAllocPool(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 347 void *allocatorPtr) final; 348 349 [[nodiscard]] Arena *TryAllocArenaForTenured(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType, 350 void *allocatorPtr); 351 352 [[nodiscard]] Arena *TryAllocArena(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType, 353 void *allocatorPtr) final; 354 355 /// @brief Allocate pool shared usage between young and tenured spaces (use for regions in G1-GC). 356 [[nodiscard]] Pool AllocSharedPool(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType, 357 void *allocatorPtr); 358 359 void IncreaseYoungOccupiedInSharedPool(size_t chunkSize); 360 361 void IncreaseTenuredOccupiedInSharedPool(size_t chunkSize); 362 363 void ReduceYoungOccupiedInSharedPool(size_t chunkSize); 364 365 void ReduceTenuredOccupiedInSharedPool(size_t chunkSize); 366 367 void FreeSharedPool(void *poolMem, size_t poolSize); 368 369 void FreeYoungPool(void *poolMem, size_t poolSize, bool releasePages = true); 370 371 void PromoteYoungPool(size_t poolSize); 372 373 void FreeTenuredPool(void *poolMem, size_t poolSize, bool releasePages = true); 374 375 size_t GetCurrentFreeTenuredSize() const; 376 377 size_t GetCurrentFreeYoungSize() const; 378 379 private: 380 void ComputeNewYoung(); 381 void UpdateYoungSize(size_t desiredYoungSize); 382 void ComputeNewTenured(); 383 384 size_t GetCurrentFreeTenuredSizeUnsafe() const; 385 size_t GetCurrentFreeYoungSizeUnsafe() const; 386 387 ObjectMemorySpace youngSpace_; 388 size_t youngSizeInSeparatePools_ {0}; 389 390 // These use for allocate shared (for young and tenured) pools and allocate blocks from them 391 size_t sharedPoolsSize_ {0}; 392 size_t youngSizeInSharedPools_ {0}; 393 size_t tenuredSizeInSharedPools_ {0}; 394 395 friend class panda::mem::test::HeapSpaceTest; 396 friend class panda::mem::test::MemStatsGenGCTest; 397 friend class panda::mem::test::RegionGarbageChoosingTest; 398 template <typename ObjectAllocator, bool REGULAR_SPACE> 399 friend class panda::mem::test::RegionAllocatorTestBase; 400 friend class panda::mem::test::RegionAllocatorTest; 401 friend class panda::mem::test::RegionNonmovableObjectAllocatorTest; 402 friend class panda::mem::test::RemSetTest; 403 }; 404 405 } // namespace panda::mem 406 407 #endif // PANDA_RUNTIME_MEM_HEAP_SPACE_H 408