• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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