• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2021-2025 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 ark::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 
SetMaxSize(size_t size)150         void SetMaxSize(size_t size)
151         {
152             maxSize_ = size;
153         }
154 
155         void ClampNewMaxSize(size_t newMaxSize);
156 
GetCurrentNonOccupiedSize()157         size_t GetCurrentNonOccupiedSize() const
158         {
159             return maxSize_ - currentSize_;
160         }
161 
UseFullSpace()162         void UseFullSpace()
163         {
164             currentSize_ = maxSize_;
165         }
166 
167         /// @brief Compute new size of heap space
168         void ComputeNewSize(size_t freeBytes, double minFreePercentage, double maxFreePercentage);
169 
170         /**
171          * @brief Increase current heap space
172          * @param bytes bytes count for heap space increasing
173          */
174         void IncreaseBy(uint64_t bytes);
175 
176         /**
177          * @brief Reduce current heap space
178          * @param bytes bytes count for heap space reducing
179          */
180         void ReduceBy(size_t bytes);
181 
182         // If we have too big pool for allocation then after space increasing we can have not memory for this pool,
183         // so we save pool size and increase heap space to allocate such pool
184         size_t savedPoolSize {0};  // NOLINT(misc-non-private-member-variables-in-classes)
185 
186     private:
187         // min_size_ <= current_size_ <= max_size_
188         size_t currentSize_ {0};
189         size_t minSize_ {0};
190         size_t maxSize_ {0};
191     };
192 
193     // For avoid zero division
194     static constexpr uint32_t MAX_FREE_PERCENTAGE = 99;
195 
196     void InitializePercentages(uint32_t minFreePercentage, uint32_t maxFreePercentage);
197 
198     [[nodiscard]] Pool TryAllocPoolBase(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType,
199                                         void *allocatorPtr, size_t currentFreeBytesInSpace, ObjectMemorySpace *memSpace,
200                                         OSPagesAllocPolicy allocPolicy = OSPagesAllocPolicy::NO_POLICY);
201 
202     [[nodiscard]] Arena *TryAllocArenaBase(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType,
203                                            void *allocatorPtr, size_t currentFreeBytesInSpace,
204                                            ObjectMemorySpace *memSpace);
205 
206     /**
207      * @brief Check that we can to allocate requested size into target space
208      *
209      * @param pool_size size of memory chunk for allocation
210      * @param current_free_bytes_in_space current freebytes count into target space
211      * @param mem_space target space in which there will be allocation
212      *
213      * @return std::optional value. If result has value then it contains bytes count for heap increasing (need during
214      * GC, for example), else need to trigger GC
215      */
216     std::optional<size_t> WillAlloc(size_t poolSize, size_t currentFreeBytesInSpace,
217                                     const ObjectMemorySpace *memSpace) const;
218 
219     /// @return current maximum size of this heap space
220     size_t GetCurrentSize() const;
221 
222     /// @return free bytes count for current heap space size
223     size_t GetCurrentFreeBytes(size_t bytesNotInThisSpace = 0) const;
224 
IsWorkGC()225     inline bool IsWorkGC() const
226     {
227         return isWorkGc_;
228     }
229 
230     mutable os::memory::RWLock heapLock_;  // NOLINT(misc-non-private-member-variables-in-classes)
231     ObjectMemorySpace memSpace_;           // NOLINT(misc-non-private-member-variables-in-classes)
232     bool isInitialized_ {false};           // NOLINT(misc-non-private-member-variables-in-classes)
233 
234 private:
235     // if GC wants allocate memory, but we have not needed memory for this then we increase current heap space
236     bool isWorkGc_ {false};
237     double minFreePercentage_ {0};
238     double maxFreePercentage_ {0};
239 
240     friend class ark::mem::test::RegionGarbageChoosingTest;
241     template <typename ObjectAllocator, bool REGULAR_SPACE>
242     friend class ark::mem::test::RegionAllocatorTestBase;
243     friend class ark::mem::test::RegionAllocatorTest;
244     friend class ark::mem::test::RegionNonmovableObjectAllocatorTest;
245     friend class ark::mem::test::RemSetTest;
246     friend class ark::mem::test::HeapSpaceTest;
247 };
248 
249 // Y - memory chunk is used for objects in young space
250 // T - memory chunk is used for objects in tenured space
251 // F - memory chunk which is not used for any space
252 //
253 //  +---------------------------------------------------------------------------------------------------------+
254 //  |                 Real object memory chunks location allocating via PoolManager                           |
255 //  |---------------------------------------------------------------------------------------------------------|
256 //  | shared pool (use for G1-GC)                        young, tenured and free pools                        |
257 //  |-----------------------------|---------------------------------------------------------------------------|
258 //  |~~~|       |   |~~~|~~~|     |~~~~~|         |~~~~~~~~~|       |~~~~~~~~~~~~~|                           |
259 //  |~~~|       |   |~~~|~~~|     |~~~~~|    F    |~~~~~~~~~|   F   |~~~~~~~~~~~~~|                           |
260 //  |~Y~|   F   | F |~Y~|~T~|  F  |~~Y~~|  (free  |~~~~T~~~~| (free |~~~~~~T~~~~~~|  non-occupied memory (F)  |
261 //  |~~~|       |   |~~~|~~~|     |~~~~~|   pool  |~~~~~~~~~|  pool |~~~~~~~~~~~~~|                           |
262 //  |~~~|       |   |~~~|~~~|     |~~~~~|   map)  |~~~~~~~~~|  map) |~~~~~~~~~~~~~|                           |
263 //  +---------------------------------------------------------------------------------------------------------+
264 //  ^ |               |   |          |                 |                   |      ^                           ^
265 //  | |               |   |          |                 |        +----------+      |                           |
266 //  | |   +-----------+   |          |                 |        |                 |                           |
267 //  | |   |    +----------|----------+  +--------------+        |    all occupied memory via PoolManager      |
268 //  | |   |    |          +-------+     |          +------------+                                             |
269 //  | |   |    |                  |     |          |                                                          |
270 //  v v   v    v                  v     v          v                                                          v
271 //  +---------------------------|-----------------------------------------------------------------------------+
272 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
273 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
274 //  |~Y~|~Y~|~~Y~~|  F  |   F   |~T~|~~~T~~~|~~~~~~T~~~~~~|            F            |            F            |
275 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
276 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
277 //  |-------------|-----|-------|-------------------------|-------------------------|-------------------------|
278 //  |     used    |     |       |          used           |                         |                         |
279 //  |-------------------|-------|---------------------------------------------------|-------------------------|
280 //  | current max size  |       |               current max size                    |                         |
281 //  |---------------------------|-----------------------------------------------------------------------------|
282 //  |        Young space        |                            Tenured space                                    |
283 //  |---------------------------|-----------------------------------------------------------------------------|
284 //  |                    young-space-size                                                            object-memory-pool
285 //  |                       argument                                                                      argument
286 //  |---------------------------------------------------------------------------------------------------------|
287 //  |                                   Generations memory representation                                     |
288 //  +---------------------------------------------------------------------------------------------------------+
289 //
290 //  init-young-space-size argument set minimum (initial) current max size for Young space
291 //  init-object-memory-pool argument set minimum (initial) current max size for heap
292 /**
293  * Class for description of object spaces and limits (minimum, maximum, current sizes) for generatinal-based GC.
294  * Pools for young and tenured spaces is allocated via this class. Also this class cooperate with PoolManager for info
295  * getting about object spaces. If current max size is not enough for new pool in some space then need to trigger GC
296  */
297 class GenerationalSpaces final : public HeapSpace {
298 public:
299     explicit GenerationalSpaces() = default;
300     NO_COPY_SEMANTIC(GenerationalSpaces);
301     NO_MOVE_SEMANTIC(GenerationalSpaces);
302     ~GenerationalSpaces() override = default;
303 
304     void Initialize(size_t initialYoungSize, bool wasSetInitialYoungSize, size_t maxYoungSize, bool wasSetMaxYoungSize,
305                     size_t initialTotalSize, size_t maxTotalSize, uint32_t minFreePercentage,
306                     uint32_t maxFreePercentage);
307 
308     /// @brief Compute new sizes for young and tenured spaces
309     void ComputeNewSize() override;
310 
311     void UpdateSize(size_t desiredYoungSize);
312 
313     size_t GetHeapSize() const override;
314 
315     size_t UpdateYoungSpaceMaxSize(size_t size);
316     // Use for CanAllocInSpace
317     static constexpr bool IS_YOUNG_SPACE = true;
318     static constexpr bool IS_TENURED_SPACE = false;
319 
320     /**
321      * @return true if we can allocate requested size in space
322      *
323      * @param is_young young or tenured space
324      * @param chunk_size memory size for allocating in space
325      */
326     bool CanAllocInSpace(bool isYoung, size_t chunkSize) const;
327 
328     size_t GetCurrentYoungSize() const;
329 
330     size_t GetMaxYoungSize() const;
331 
332     void UseFullYoungSpace();
333 
334     /// @brief Allocate alone young pool (use for Gen-GC) with maximum possible size of young space
335     [[nodiscard]] Pool AllocAlonePoolForYoung(SpaceType spaceType, AllocatorType allocatorType, void *allocatorPtr);
336 
337     /**
338      * @brief Try allocate pool for young space (use for G1-GC).
339      * If free size in young space less requested pool size then pool can be allocate only during GC work
340      */
341     [[nodiscard]] Pool TryAllocPoolForYoung(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType,
342                                             void *allocatorPtr);
343 
344     /**
345      * @brief Try allocate pool for tenured space (use for generational-based GC).
346      * If free size in tenured space less requested pool size then pool can be allocate only during GC work
347      */
348     [[nodiscard]] Pool TryAllocPoolForTenured(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType,
349                                               void *allocatorPtr,
350                                               OSPagesAllocPolicy allocPolicy = OSPagesAllocPolicy::NO_POLICY);
351 
352     [[nodiscard]] Pool TryAllocPool(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType,
353                                     void *allocatorPtr) final;
354 
355     [[nodiscard]] Arena *TryAllocArenaForTenured(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType,
356                                                  void *allocatorPtr);
357 
358     [[nodiscard]] Arena *TryAllocArena(size_t arenaSize, SpaceType spaceType, AllocatorType allocatorType,
359                                        void *allocatorPtr) final;
360 
361     /// @brief Allocate pool shared usage between young and tenured spaces (use for regions in G1-GC).
362     [[nodiscard]] Pool AllocSharedPool(size_t poolSize, SpaceType spaceType, AllocatorType allocatorType,
363                                        void *allocatorPtr);
364 
365     void IncreaseYoungOccupiedInSharedPool(size_t chunkSize);
366 
367     void IncreaseTenuredOccupiedInSharedPool(size_t chunkSize);
368 
369     void ReduceYoungOccupiedInSharedPool(size_t chunkSize);
370 
371     void ReduceTenuredOccupiedInSharedPool(size_t chunkSize);
372 
373     void FreeSharedPool(void *poolMem, size_t poolSize);
374 
375     void FreeYoungPool(void *poolMem, size_t poolSize, bool releasePages = true);
376 
377     void PromoteYoungPool(size_t poolSize);
378 
379     void FreeTenuredPool(void *poolMem, size_t poolSize, bool releasePages = true);
380 
381     size_t GetCurrentFreeTenuredSize() const;
382 
383     size_t GetCurrentFreeYoungSize() const;
384 
385 private:
386     void ComputeNewYoung();
387     void UpdateYoungSize(size_t desiredYoungSize);
388     void ComputeNewTenured();
389 
390     size_t GetCurrentFreeTenuredSizeUnsafe() const;
391     size_t GetCurrentFreeYoungSizeUnsafe() const;
392 
393     ObjectMemorySpace youngSpace_;
394     size_t youngSizeInSeparatePools_ {0};
395 
396     // These use for allocate shared (for young and tenured) pools and allocate blocks from them
397     size_t sharedPoolsSize_ {0};
398     size_t youngSizeInSharedPools_ {0};
399     size_t tenuredSizeInSharedPools_ {0};
400 
401     friend class ark::mem::test::HeapSpaceTest;
402     friend class ark::mem::test::MemStatsGenGCTest;
403     friend class ark::mem::test::RegionGarbageChoosingTest;
404     template <typename ObjectAllocator, bool REGULAR_SPACE>
405     friend class ark::mem::test::RegionAllocatorTestBase;
406     friend class ark::mem::test::RegionAllocatorTest;
407     friend class ark::mem::test::RegionNonmovableObjectAllocatorTest;
408     friend class ark::mem::test::RemSetTest;
409 };
410 
411 }  // namespace ark::mem
412 
413 #endif  // PANDA_RUNTIME_MEM_HEAP_SPACE_H
414