1 /*
   2  * Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2020 SAP SE. All rights reserved.
   4  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   5  *
   6  * This code is free software; you can redistribute it and/or modify it
   7  * under the terms of the GNU General Public License version 2 only, as
   8  * published by the Free Software Foundation.
   9  *
  10  * This code is distributed in the hope that it will be useful, but WITHOUT
  11  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  13  * version 2 for more details (a copy is included in the LICENSE file that
  14  * accompanied this code).
  15  *
  16  * You should have received a copy of the GNU General Public License version
  17  * 2 along with this work; if not, write to the Free Software Foundation,
  18  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  19  *
  20  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  21  * or visit www.oracle.com if you need additional information or have any
  22  * questions.
  23  *
  24  */
  25 
  26 #ifndef SHARE_MEMORY_METASPACE_MSARENA_HPP
  27 #define SHARE_MEMORY_METASPACE_MSARENA_HPP
  28 
  29 #include "memory/allocation.hpp"
  30 #include "memory/metaspace/msChunkManager.hpp"
  31 #include "memory/metaspace/msCommon.hpp"
  32 #include "memory/metaspace/msCounter.hpp"
  33 #include "memory/metaspace/msMetachunk.hpp"
  34 #include "memory/metaspace/msMetachunkList.hpp"
  35 #include "memory/metaspace.hpp"
  36 
  37 class outputStream;
  38 class Mutex;
  39 
  40 namespace metaspace {
  41 
  42 class ArenaGrowthPolicy;
  43 class FreeBlocks;
  44 
  45 struct ArenaStats;
  46 
  47 // The MetaspaceArena is a growable metaspace memory pool belonging to a CLD;
  48 //  internally it consists of a list of metaspace chunks, of which the head chunk
  49 //  is the current chunk from which we allocate via pointer bump.
  50 //
  51 //  +---------------+
  52 //  |     Arena     |
  53 //  +---------------+
  54 //            |
  55 //            | _chunks                                               commit top
  56 //            |                                                       v
  57 //        +----------+      +----------+      +----------+      +----------+
  58 //        | retired  | ---> | retired  | ---> | retired  | ---> | current  |
  59 //        | chunk    |      | chunk    |      | chunk    |      | chunk    |
  60 //        +----------+      +----------+      +----------+      +----------+
  61 //                                                                  ^
  62 //                                                                  used top
  63 //
  64 //        +------------+
  65 //        | FreeBlocks | --> O -> O -> O -> O
  66 //        +------------+
  67 //
  68 //
  69 
  70 // When the current chunk is used up, MetaspaceArena requestes a new chunk from
  71 //  the associated ChunkManager.
  72 //
  73 // MetaspaceArena also keeps a FreeBlocks structure to manage memory blocks which
  74 //  had been deallocated prematurely.
  75 //
  76 
  77 class MetaspaceArena : public CHeapObj<mtClass> {
  78 
  79   // Reference to an outside lock to use for synchronizing access to this arena.
  80   //  This lock is normally owned by the CLD which owns the ClassLoaderMetaspace which
  81   //  owns this arena.
  82   // Todo: This should be changed. Either the CLD should synchronize access to the
  83   //       CLMS and its arenas itself, or the arena should have an own lock. The latter
  84   //       would allow for more fine granular locking since it would allow access to
  85   //       both class- and non-class arena in the CLMS independently.
  86   Mutex* const _lock;
  87 
  88   // Reference to the chunk manager to allocate chunks from.
  89   ChunkManager* const _chunk_manager;
  90 
  91   // Reference to the growth policy to use.
  92   const ArenaGrowthPolicy* const _growth_policy;
  93 
  94   // List of chunks. Head of the list is the current chunk.
  95   MetachunkList _chunks;
  96 
  97   // Structure to take care of leftover/deallocated space in used chunks.
  98   // Owned by the Arena. Gets allocated on demand only.
  99   FreeBlocks* _fbl;
 100 
 101   Metachunk* current_chunk()              { return _chunks.first(); }
 102   const Metachunk* current_chunk() const  { return _chunks.first(); }
 103 
 104   // Reference to an outside counter to keep track of used space.
 105   SizeAtomicCounter* const _total_used_words_counter;
 106 
 107   // A name for purely debugging/logging purposes.
 108   const char* const _name;
 109 
 110   Mutex* lock() const                           { return _lock; }
 111   ChunkManager* chunk_manager() const           { return _chunk_manager; }
 112 
 113   // free block list
 114   FreeBlocks* fbl() const                       { return _fbl; }
 115   void add_allocation_to_fbl(MetaWord* p, size_t word_size);
 116 
 117   // Given a chunk, add its remaining free committed space to the free block list.
 118   void salvage_chunk(Metachunk* c);
 119 
 120   // Allocate a new chunk from the underlying chunk manager able to hold at least
 121   // requested word size.
 122   Metachunk* allocate_new_chunk(size_t requested_word_size);
 123 
 124   // Returns the level of the next chunk to be added, acc to growth policy.
 125   chunklevel_t next_chunk_level() const;
 126 
 127   // Attempt to enlarge the current chunk to make it large enough to hold at least
 128   //  requested_word_size additional words.
 129   //
 130   // On success, true is returned, false otherwise.
 131   bool attempt_enlarge_current_chunk(size_t requested_word_size);
 132 
 133   // Prematurely returns a metaspace allocation to the _block_freelists
 134   // because it is not needed anymore (requires CLD lock to be active).
 135   void deallocate_locked(MetaWord* p, size_t word_size);
 136 
 137   // Returns true if the area indicated by pointer and size have actually been allocated
 138   // from this arena.
 139   DEBUG_ONLY(bool is_valid_area(MetaWord* p, size_t word_size) const;)
 140 
 141 public:
 142 
 143   MetaspaceArena(ChunkManager* chunk_manager,
 144                const ArenaGrowthPolicy* growth_policy,
 145                Mutex* lock,
 146                SizeAtomicCounter* total_used_words_counter,
 147                const char* name);
 148 
 149   ~MetaspaceArena();
 150 
 151   // Allocate memory from Metaspace.
 152   // 1) Attempt to allocate from the dictionary of deallocated blocks.
 153   // 2) Attempt to allocate from the current chunk.
 154   // 3) Attempt to enlarge the current chunk in place if it is too small.
 155   // 4) Attempt to get a new chunk and allocate from that chunk.
 156   // At any point, if we hit a commit limit, we return NULL.
 157   MetaWord* allocate(size_t word_size);
 158 
 159   // Prematurely returns a metaspace allocation to the _block_freelists because it is not
 160   // needed anymore.
 161   void deallocate(MetaWord* p, size_t word_size);
 162 
 163   // Update statistics. This walks all in-use chunks.
 164   void add_to_statistics(ArenaStats* out) const;
 165 
 166   // Convenience method to get the most important usage statistics.
 167   // For deeper analysis use add_to_statistics().
 168   void usage_numbers(size_t* p_used_words, size_t* p_committed_words, size_t* p_capacity_words) const;
 169 
 170   DEBUG_ONLY(void verify() const;)
 171   DEBUG_ONLY(void verify_locked() const;)
 172 
 173   void print_on(outputStream* st) const;
 174   void print_on_locked(outputStream* st) const;
 175 
 176 };
 177 
 178 } // namespace metaspace
 179 
 180 #endif // SHARE_MEMORY_METASPACE_MSARENA_HPP
 181