• 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 RegularSpace>
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 initial_size, size_t max_size, uint32_t min_free_percentage, uint32_t max_free_percentage);
86 
87     /**
88      * \brief Compute new size of heap space
89      */
90     virtual void ComputeNewSize();
91 
92     /**
93      * \brief Get current used heap size
94      */
95     virtual size_t GetHeapSize() const;
96 
97     /**
98      * \brief Try to allocate pool via PoolManager
99      */
100     [[nodiscard]] virtual Pool TryAllocPool(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
101                                             void *allocator_ptr);
102 
103     /**
104      * \brief Try to allocate arena via PoolManager
105      */
106     [[nodiscard]] virtual Arena *TryAllocArena(size_t arena_size, SpaceType space_type, AllocatorType allocator_type,
107                                                void *allocator_ptr);
108 
109     /**
110      * \brief Free pool via PoolManager
111      */
112     void FreePool(void *pool_mem, size_t pool_size);
113 
114     /**
115      * \brief Free arena via PoolManager
116      */
117     void FreeArena(Arena *arena);
118 
GetMinFreePercentage()119     double GetMinFreePercentage() const
120     {
121         return min_free_percentage_;
122     }
123 
GetMaxFreePercentage()124     double GetMaxFreePercentage() const
125     {
126         return max_free_percentage_;
127     }
128 
SetIsWorkGC(bool value)129     void SetIsWorkGC(bool value)
130     {
131         is_work_gc_ = value;
132     }
133 
134 protected:
135     class ObjectMemorySpace {
136     public:
137         explicit ObjectMemorySpace() = default;
138         DEFAULT_COPY_SEMANTIC(ObjectMemorySpace);
139         DEFAULT_NOEXCEPT_MOVE_SEMANTIC(ObjectMemorySpace);
140         ~ObjectMemorySpace() = default;
141 
142         void Initialize(size_t initial_size, size_t max_size);
143 
GetCurrentSize()144         size_t GetCurrentSize() const
145         {
146             return current_size_;
147         }
148 
GetMaxSize()149         size_t GetMaxSize() const
150         {
151             return max_size_;
152         }
153 
GetCurrentNonOccupiedSize()154         size_t GetCurrentNonOccupiedSize() const
155         {
156             return max_size_ - current_size_;
157         }
158 
UseFullSpace()159         void UseFullSpace()
160         {
161             current_size_ = max_size_;
162         }
163 
164         /**
165          * \brief Compute new size of heap space
166          */
167         void ComputeNewSize(size_t free_bytes, double min_free_percentage, double max_free_percentage);
168 
169         /**
170          * \brief Increase current heap space
171          * @param bytes bytes count for heap space increasing
172          */
173         void IncreaseBy(uint64_t bytes);
174 
175         /**
176          * \brief Reduce current heap space
177          * @param bytes bytes count for heap space reducing
178          */
179         void ReduceBy(size_t bytes);
180 
181         // If we have too big pool for allocation then after space increasing we can have not memory for this pool,
182         // so we save pool size and increase heap space to allocate such pool
183         size_t saved_pool_size {0};  // NOLINT(misc-non-private-member-variables-in-classes)
184 
185     private:
186         // min_size_ <= current_size_ <= max_size_
187         size_t current_size_ {0};
188         size_t min_size_ {0};
189         size_t max_size_ {0};
190     };
191 
192     // For avoid zero division
193     static constexpr uint32_t MAX_FREE_PERCENTAGE = 99;
194 
195     void InitializePercentages(uint32_t min_free_percentage, uint32_t max_free_percentage);
196 
197     [[nodiscard]] Pool TryAllocPoolBase(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
198                                         void *allocator_ptr, size_t current_free_bytes_in_space,
199                                         ObjectMemorySpace *mem_space);
200 
201     [[nodiscard]] Arena *TryAllocArenaBase(size_t arena_size, SpaceType space_type, AllocatorType allocator_type,
202                                            void *allocator_ptr, size_t current_free_bytes_in_space,
203                                            ObjectMemorySpace *mem_space);
204 
205     /**
206      * \brief Check that we can to allocate requested size into target space
207      *
208      * @param pool_size size of memory chunk for allocation
209      * @param current_free_bytes_in_space current freebytes count into target space
210      * @param mem_space target space in which there will be allocation
211      *
212      * @return std::optional value. If result has value then it contains bytes count for heap increasing (need during
213      * GC, for example), else need to trigger GC
214      */
215     std::optional<size_t> WillAlloc(size_t pool_size, size_t current_free_bytes_in_space,
216                                     const ObjectMemorySpace *mem_space) const;
217 
218     /**
219      * @return current maximum size of this heap space
220      */
221     size_t GetCurrentSize() const;
222 
223     /**
224      * @return free bytes count for current heap space size
225      */
226     size_t GetCurrentFreeBytes(size_t bytes_not_in_this_space = 0) const;
227 
IsWorkGC()228     inline bool IsWorkGC() const
229     {
230         return is_work_gc_;
231     }
232 
233     mutable os::memory::RWLock heap_lock_;  // NOLINT(misc-non-private-member-variables-in-classes)
234     ObjectMemorySpace mem_space_;           // NOLINT(misc-non-private-member-variables-in-classes)
235     bool is_initialized_ {false};           // NOLINT(misc-non-private-member-variables-in-classes)
236 
237 private:
238     // if GC wants allocate memory, but we have not needed memory for this then we increase current heap space
239     bool is_work_gc_ {false};
240     double min_free_percentage_ {0};
241     double max_free_percentage_ {0};
242 
243     friend class panda::mem::test::RegionGarbageChoosingTest;
244     template <typename ObjectAllocator, bool RegularSpace>
245     friend class panda::mem::test::RegionAllocatorTestBase;
246     friend class panda::mem::test::RegionAllocatorTest;
247     friend class panda::mem::test::RegionNonmovableObjectAllocatorTest;
248     friend class panda::mem::test::RemSetTest;
249     friend class panda::mem::test::HeapSpaceTest;
250 };
251 
252 // Y - memory chunk is used for objects in young space
253 // T - memory chunk is used for objects in tenured space
254 // F - memory chunk which is not used for any space
255 //
256 //  +---------------------------------------------------------------------------------------------------------+
257 //  |                 Real object memory chunks location allocating via PoolManager                           |
258 //  |---------------------------------------------------------------------------------------------------------|
259 //  | shared pool (use for G1-GC)                        young, tenured and free pools                        |
260 //  |-----------------------------|---------------------------------------------------------------------------|
261 //  |~~~|       |   |~~~|~~~|     |~~~~~|         |~~~~~~~~~|       |~~~~~~~~~~~~~|                           |
262 //  |~~~|       |   |~~~|~~~|     |~~~~~|    F    |~~~~~~~~~|   F   |~~~~~~~~~~~~~|                           |
263 //  |~Y~|   F   | F |~Y~|~T~|  F  |~~Y~~|  (free  |~~~~T~~~~| (free |~~~~~~T~~~~~~|  non-occupied memory (F)  |
264 //  |~~~|       |   |~~~|~~~|     |~~~~~|   pool  |~~~~~~~~~|  pool |~~~~~~~~~~~~~|                           |
265 //  |~~~|       |   |~~~|~~~|     |~~~~~|   map)  |~~~~~~~~~|  map) |~~~~~~~~~~~~~|                           |
266 //  +---------------------------------------------------------------------------------------------------------+
267 //  ^ |               |   |          |                 |                   |      ^                           ^
268 //  | |               |   |          |                 |        +----------+      |                           |
269 //  | |   +-----------+   |          |                 |        |                 |                           |
270 //  | |   |    +----------|----------+  +--------------+        |    all occupied memory via PoolManager      |
271 //  | |   |    |          +-------+     |          +------------+                                             |
272 //  | |   |    |                  |     |          |                                                          |
273 //  v v   v    v                  v     v          v                                                          v
274 //  +---------------------------|-----------------------------------------------------------------------------+
275 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
276 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
277 //  |~Y~|~Y~|~~Y~~|  F  |   F   |~T~|~~~T~~~|~~~~~~T~~~~~~|            F            |            F            |
278 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
279 //  |~~~|~~~|~~~~~|     |       |~~~|~~~~~~~|~~~~~~~~~~~~~|                         |                         |
280 //  |-------------|-----|-------|-------------------------|-------------------------|-------------------------|
281 //  |     used    |     |       |          used           |                         |                         |
282 //  |-------------------|-------|---------------------------------------------------|-------------------------|
283 //  | current max size  |       |               current max size                    |                         |
284 //  |---------------------------|-----------------------------------------------------------------------------|
285 //  |        Young space        |                            Tenured space                                    |
286 //  |---------------------------|-----------------------------------------------------------------------------|
287 //  |                    young-space-size                                                            object-memory-pool
288 //  |                       argument                                                                      argument
289 //  |---------------------------------------------------------------------------------------------------------|
290 //  |                                   Generations memory representation                                     |
291 //  +---------------------------------------------------------------------------------------------------------+
292 //
293 //  init-young-space-size argument set minimum (initial) current max size for Young space
294 //  init-object-memory-pool argument set minimum (initial) current max size for heap
295 /**
296  * Class for description of object spaces and limits (minimum, maximum, current sizes) for generatinal-based GC.
297  * Pools for young and tenured spaces is allocated via this class. Also this class cooperate with PoolManager for info
298  * getting about object spaces. If current max size is not enough for new pool in some space then need to trigger GC
299  */
300 class GenerationalSpaces final : public HeapSpace {
301 public:
302     explicit GenerationalSpaces() = default;
303     NO_COPY_SEMANTIC(GenerationalSpaces);
304     NO_MOVE_SEMANTIC(GenerationalSpaces);
305     ~GenerationalSpaces() override = default;
306 
307     void Initialize(size_t initial_young_size, bool was_set_initial_young_size, size_t max_young_size,
308                     bool was_set_max_young_size, size_t initial_total_size, size_t max_total_size,
309                     uint32_t min_free_percentage, uint32_t max_free_percentage);
310 
311     /**
312      * \brief Compute new sizes for young and tenured spaces
313      */
314     void ComputeNewSize() override;
315 
316     size_t GetHeapSize() const override;
317 
318     // Use for CanAllocInSpace
319     static constexpr bool IS_YOUNG_SPACE = true;
320     static constexpr bool IS_TENURED_SPACE = false;
321 
322     /**
323      * @return true if we can allocate requested size in space
324      *
325      * @param is_young young or tenured space
326      * @param chunk_size memory size for allocating in space
327      */
328     bool CanAllocInSpace(bool is_young, size_t chunk_size) const;
329 
330     size_t GetCurrentMaxYoungSize() const;
331 
332     size_t GetMaxYoungSize() const;
333 
334     void UseFullYoungSpace();
335 
336     /**
337      * \brief Allocate alone young pool (use for Gen-GC) with maximum possible size of young space
338      */
339     [[nodiscard]] Pool AllocAlonePoolForYoung(SpaceType space_type, AllocatorType allocator_type, void *allocator_ptr);
340 
341     /**
342      * \brief Try allocate pool for young space (use for G1-GC).
343      * If free size in young space less requested pool size then pool can be allocate only during GC work
344      */
345     [[nodiscard]] Pool TryAllocPoolForYoung(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
346                                             void *allocator_ptr);
347 
348     /**
349      * \brief Try allocate pool for tenured space (use for generational-based GC).
350      * If free size in tenured space less requested pool size then pool can be allocate only during GC work
351      */
352     [[nodiscard]] Pool TryAllocPoolForTenured(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
353                                               void *allocator_ptr);
354 
355     [[nodiscard]] Pool TryAllocPool(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
356                                     void *allocator_ptr) final;
357 
358     [[nodiscard]] Arena *TryAllocArenaForTenured(size_t arena_size, SpaceType space_type, AllocatorType allocator_type,
359                                                  void *allocator_ptr);
360 
361     [[nodiscard]] Arena *TryAllocArena(size_t arena_size, SpaceType space_type, AllocatorType allocator_type,
362                                        void *allocator_ptr) final;
363 
364     /**
365      * \brief Allocate pool shared usage between young and tenured spaces (use for regions in G1-GC).
366      */
367     [[nodiscard]] Pool AllocSharedPool(size_t pool_size, SpaceType space_type, AllocatorType allocator_type,
368                                        void *allocator_ptr);
369 
370     void IncreaseYoungOccupiedInSharedPool(size_t chunk_size);
371 
372     void IncreaseTenuredOccupiedInSharedPool(size_t chunk_size);
373 
374     void ReduceYoungOccupiedInSharedPool(size_t chunk_size);
375 
376     void ReduceTenuredOccupiedInSharedPool(size_t chunk_size);
377 
378     void FreeSharedPool(void *pool_mem, size_t pool_size);
379 
380     void FreeYoungPool(void *pool_mem, size_t pool_size);
381 
382     void PromoteYoungPool(size_t pool_size);
383 
384     void FreeTenuredPool(void *pool_mem, size_t pool_size);
385 
386     size_t GetCurrentFreeTenuredSize() const;
387 
388     size_t GetCurrentFreeYoungSize() const;
389 
390 private:
391     void ComputeNewYoung();
392     void ComputeNewTenured();
393 
394     size_t GetCurrentFreeTenuredSizeUnsafe() const;
395     size_t GetCurrentFreeYoungSizeUnsafe() const;
396 
397     ObjectMemorySpace young_space_;
398     size_t young_size_in_separate_pools_ {0};
399 
400     // These use for allocate shared (for young and tenured) pools and allocate blocks from them
401     size_t shared_pools_size_ {0};
402     size_t young_size_in_shared_pools_ {0};
403     size_t tenured_size_in_shared_pools_ {0};
404 
405     friend class panda::mem::test::HeapSpaceTest;
406     friend class panda::mem::test::MemStatsGenGCTest;
407     friend class panda::mem::test::RegionGarbageChoosingTest;
408     template <typename ObjectAllocator, bool RegularSpace>
409     friend class panda::mem::test::RegionAllocatorTestBase;
410     friend class panda::mem::test::RegionAllocatorTest;
411     friend class panda::mem::test::RegionNonmovableObjectAllocatorTest;
412     friend class panda::mem::test::RemSetTest;
413 };
414 
415 }  // namespace panda::mem
416 
417 #endif  // PANDA_RUNTIME_MEM_HEAP_SPACE_H
418