< prev index next >

src/hotspot/share/memory/metaspace/metachunk.hpp

Print this page
rev 60538 : imported patch jep387-core.patch
   1 /*
   2  * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.

   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.
   8  *
   9  * This code is distributed in the hope that it will be useful, but WITHOUT
  10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  12  * version 2 for more details (a copy is included in the LICENSE file that
  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  *
  23  */

  24 #ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
  25 #define SHARE_MEMORY_METASPACE_METACHUNK_HPP
  26 
  27 #include "memory/metaspace/metabase.hpp"
  28 #include "memory/metaspace/metaspaceCommon.hpp"

  29 #include "utilities/debug.hpp"
  30 #include "utilities/globalDefinitions.hpp"
  31 
  32 class MetachunkTest;

  33 
  34 namespace metaspace {
  35 
  36 class VirtualSpaceNode;
  37 
  38 //  Metachunk - Quantum of allocation from a Virtualspace
  39 //    Metachunks are reused (when freed are put on a global freelist) and
  40 //    have no permanent association to a SpaceManager.









































  41 
  42 //            +--------------+ <- end    --+       --+
  43 //            |              |             |         |
  44 //            |              |             | free    |
  45 //            |              |             |         |
  46 //            |              |             |         | size | capacity
  47 //            |              |             |         |
  48 //            |              | <- top   -- +         |
  49 //            |              |             |         |
  50 //            |              |             | used    |
  51 //            |              |             |         |

  52 //            |              |             |         |
  53 //            +--------------+ <- bottom --+       --+
  54 
  55 enum ChunkOrigin {
  56   // Chunk normally born (via take_from_committed)
  57   origin_normal = 1,
  58   // Chunk was born as padding chunk
  59   origin_pad = 2,
  60   // Chunk was born as leftover chunk in VirtualSpaceNode::retire
  61   origin_leftover = 3,
  62   // Chunk was born as result of a merge of smaller chunks
  63   origin_merge = 4,
  64   // Chunk was born as result of a split of a larger chunk
  65   origin_split = 5,
  66 
  67   origin_minimum = origin_normal,
  68   origin_maximum = origin_split,
  69   origins_count = origin_maximum + 1
  70 };
  71 
  72 inline bool is_valid_chunkorigin(ChunkOrigin origin) {
  73   return origin == origin_normal ||
  74     origin == origin_pad ||
  75     origin == origin_leftover ||
  76     origin == origin_merge ||
  77     origin == origin_split;
  78 }
  79 
  80 class Metachunk : public Metabase<Metachunk> {
  81 
  82   friend class ::MetachunkTest;
  83 
  84   // The VirtualSpaceNode containing this chunk.
  85   VirtualSpaceNode* const _container;
  86 
  87   // Current allocation top.
  88   MetaWord* _top;
  89 
  90   // A 32bit sentinel for debugging purposes.
  91   enum { CHUNK_SENTINEL = 0x4d4554EF,  // "MET"
  92          CHUNK_SENTINEL_INVALID = 0xFEEEEEEF






  93   };

  94 
  95   uint32_t _sentinel;
  96 
  97   const ChunkIndex _chunk_type;
  98   const bool _is_class;
  99   // Whether the chunk is free (in freelist) or in use by some class loader.
 100   bool _is_tagged_free;
 101 
 102   ChunkOrigin _origin;
 103   int _use_count;
 104 
 105   MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
 106   MetaWord* top() const         { return _top; }
 107 
 108  public:
 109   // Metachunks are allocated out of a MetadataVirtualSpace and
 110   // and use some of its space to describe itself (plus alignment
 111   // considerations).  Metadata is allocated in the rest of the chunk.
 112   // This size is the overhead of maintaining the Metachunk within
 113   // the space.





















































































































































 114 
 115   // Alignment of each allocation in the chunks.
 116   static size_t object_alignment();
 117 
 118   // Size of the Metachunk header, in words, including alignment.
 119   static size_t overhead();
 120 
 121   Metachunk(ChunkIndex chunktype, bool is_class, size_t word_size, VirtualSpaceNode* container);
 122 
 123   MetaWord* allocate(size_t word_size);
 124 
 125   VirtualSpaceNode* container() const { return _container; }
 126 
 127   MetaWord* bottom() const { return (MetaWord*) this; }
 128 
 129   // Reset top to bottom so chunk can be reused.
 130   void reset_empty() { _top = initial_top(); clear_next(); clear_prev(); }
 131   bool is_empty() { return _top == initial_top(); }
 132 
 133   // used (has been allocated)
 134   // free (available for future allocations)
 135   size_t word_size() const { return size(); }
 136   size_t used_word_size() const;
 137   size_t free_word_size() const;
 138 
 139   bool is_tagged_free() { return _is_tagged_free; }
 140   void set_is_tagged_free(bool v) { _is_tagged_free = v; }
 141 
 142   bool contains(const void* ptr) { return bottom() <= ptr && ptr < _top; }
 143 
 144   void print_on(outputStream* st) const;
 145 
 146   bool is_valid_sentinel() const        { return _sentinel == CHUNK_SENTINEL; }
 147   void remove_sentinel()                { _sentinel = CHUNK_SENTINEL_INVALID; }
 148 
 149   int get_use_count() const             { return _use_count; }
 150   void inc_use_count()                  { _use_count ++; }
 151 
 152   ChunkOrigin get_origin() const        { return _origin; }
 153   void set_origin(ChunkOrigin orig)     { _origin = orig; }
 154 
 155   ChunkIndex get_chunk_type() const     { return _chunk_type; }
 156   bool is_class() const                 { return _is_class; }
 157 
 158   DEBUG_ONLY(void mangle(juint word_value);)
 159   DEBUG_ONLY(void verify() const;)
 160 
 161 };
 162 



 163 
 164 // Helper function that does a bunch of checks for a chunk.
 165 DEBUG_ONLY(void do_verify_chunk(Metachunk* chunk);)
 166 
 167 // Given a Metachunk, update its in-use information (both in the
 168 // chunk and the occupancy map).
 169 void do_update_in_use_info_for_chunk(Metachunk* chunk, bool inuse);
 170 
 171 } // namespace metaspace
 172 
 173 #endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
   1 /*
   2  * Copyright (c) 2012, 2020, Oracle and/or its affiliates. All rights reserved.
   3  * Copyright (c) 2017, 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_METACHUNK_HPP
  27 #define SHARE_MEMORY_METASPACE_METACHUNK_HPP
  28 
  29 
  30 #include "memory/metaspace/counter.hpp"
  31 #include "memory/metaspace/chunkLevel.hpp"
  32 #include "utilities/debug.hpp"
  33 #include "utilities/globalDefinitions.hpp"
  34 
  35 
  36 class outputStream;
  37 
  38 namespace metaspace {
  39 
  40 class VirtualSpaceNode;
  41 
  42 // A Metachunk is a contiguous metaspace memory region. It is part of
  43 // a MetaspaceArena, which keeps a list of MetaChunk and allocates via
  44 // pointer bump from the top element in the list.
  45 //
  46 // The Metachunk object itself (the "chunk header") is separated from
  47 //  the memory region (the chunk payload) it describes. It also can have
  48 //  no payload (a "dead" chunk). In itself it lives in C-heap, managed
  49 //  as part of a pool of Metachunk headers (ChunkHeaderPool).
  50 //
  51 // -- Metachunk state --
  52 //
  53 // A Metachunk is "in-use" if it is part of a MetaspaceArena. That means
  54 //  its memory is used - or will be used shortly - to hold VM metadata
  55 //  on behalf of a class loader.
  56 //
  57 // A Metachunk is "free" if its payload is currently unused. In that
  58 //  case it is managed by a chunk freelist (the ChunkManager).
  59 // 
  60 // A Metachunk is "dead" if it does not have a corresponding payload.
  61 //  In that case it lives as part of a freelist-of-dead-chunk-headers
  62 //  in the ChunkHeaderPool.
  63 //
  64 // -- Level --
  65 //
  66 // Metachunks are managed as part of a buddy style allocation scheme.
  67 // Sized always in steps of power-of-2, ranging from the smallest chunk size
  68 // (1Kb) to the largest (4Mb) (see chunklevel.hpp).
  69 // Its size is encoded as level, with level 0 being the largest chunk
  70 // size ("root chunk").
  71 //
  72 // -- Payload commit state --
  73 //
  74 // A Metachunk payload may be committed, partly committed or completely
  75 // uncommitted. Technically, a payload may be committed "checkered" -
  76 // i.e. committed and uncommitted parts may interleave - but the
  77 // important part is how much contiguous space is committed starting
  78 // at the base of the payload (since that's where we allocate). 
  79 // 
  80 // The Metachunk keeps track of how much space is committed starting
  81 //  at the base of the payload - which is a performace optimization - 
  82 //  while underlying layers (VirtualSpaceNode->commitmask) keep track
  83 //  of the "real" commit state, aka which granules are committed,
  84 //  independent on what chunks reside above those granules.
  85 
  86 
  87 //            +--------------+ <- end    -----------+ ----------+
  88 //            |              |                      |           |

  89 //            |              |                      |           |

  90 //            |              |                      |           |

  91 //            |              |                      |           |

  92 //            |              |                      |           |
  93 //            | -----------  | <- committed_top  -- +           |
  94 //            |              |                      |           |
  95 //            |              |                      | "free"    |
  96 //            |              |                      |           | size 
  97 //            |              |     "free_below_     |           |
  98 //            |              |        committed"    |           |
  99 //            |              |                      |           |
 100 //            |              |                      |           |
 101 //            | -----------  | <- top     --------- + --------  |
 102 //            |              |                      |           |
 103 //            |              |     "used"           |           |
 104 //            |              |                      |           |
 105 //            +--------------+ <- start   ----------+ ----------+







 106 
 107 // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace,
 108 // this class lives somewhere else.
 109 class Metachunk {
 110 
 111   // start of chunk memory; NULL if dead.
 112   MetaWord* _base;
 113 
 114   // Used words.
 115   size_t _used_words;
 116 
 117   // Size of the region, starting from base, which is guaranteed to be committed. In words.
 118   //  The actual size of committed regions may actually be larger.
 119   //
 120   //  (This is a performance optimization. The underlying VirtualSpaceNode knows
 121   //   which granules are committed; but we want to avoid having to ask.)
 122   size_t _committed_words;
 123 
 124   chunklevel_t _level; // aka size.
 125 
 126   // state_free:    free, owned by a ChunkManager
 127   // state_in_use:  in-use, owned by a MetaspaceArena
 128   // dead:          just a hollow chunk header without associated memory, owned
 129   //                 by chunk header pool.
 130   enum state_t {
 131     state_free = 0,
 132     state_in_use = 1,
 133     state_dead = 2
 134   };
 135   state_t _state;
 136 
 137   // We need unfortunately a back link to the virtual space node
 138   // for splitting and merging nodes.
 139   VirtualSpaceNode* _vsnode;
 140 
 141 
 142   // A chunk header is kept in a list:
 143   // 1 in the list of used chunks inside a MetaspaceArena, if it is in use
 144   // 2 in the list of free chunks inside a ChunkManager, if it is free
 145   // 3 in the freelist of unused headers inside the ChunkHeaderPool,
 146   //   if it is unused (e.g. result of chunk merging) and has no associated
 147   //   memory area.
 148   Metachunk* _prev;
 149   Metachunk* _next;
 150 
 151   // Furthermore, we keep, per chunk, information about the neighboring chunks.
 152   // This is needed to split and merge chunks.
 153   //
 154   // Note: These members can be modified concurrently while a chunk is alive and in use.
 155   // This can happen if a neighboring chunk is added or removed.
 156   // This means only read or modify these members under expand lock protection.
 157   Metachunk* _prev_in_vs;
 158   Metachunk* _next_in_vs;
 159 
 160   // Commit uncommitted section of the chunk.
 161   // Fails if we hit a commit limit.
 162   bool commit_up_to(size_t new_committed_words);
 163 
 164   DEBUG_ONLY(static void assert_have_expand_lock();)
 165 
 166 public:
 167 
 168   Metachunk()
 169     : _base(NULL),
 170       _used_words(0),
 171       _committed_words(0),
 172       _level(chunklevel::ROOT_CHUNK_LEVEL),
 173       _state(state_free),
 174       _vsnode(NULL),
 175       _prev(NULL), _next(NULL),
 176       _prev_in_vs(NULL), _next_in_vs(NULL)
 177   {}
 178 
 179  void clear() {
 180    _base = NULL;
 181    _used_words = 0;
 182    _committed_words = 0;
 183    _level = chunklevel::ROOT_CHUNK_LEVEL;
 184    _state = state_free;
 185    _vsnode = NULL;
 186    _prev = NULL;
 187    _next = NULL;
 188    _prev_in_vs = NULL;
 189    _next_in_vs = NULL;
 190   }
 191 
 192 
 193   size_t word_size() const        { return chunklevel::word_size_for_level(_level); }
 194 
 195   MetaWord* base() const          { return _base; }
 196   MetaWord* top() const           { return base() + _used_words; }
 197   MetaWord* committed_top() const { return base() + _committed_words; }
 198   MetaWord* end() const           { return base() + word_size(); }
 199 
 200   // Chunk list wiring
 201   void set_prev(Metachunk* c)     { _prev = c; }
 202   Metachunk* prev() const         { return _prev; }
 203   void set_next(Metachunk* c)     { _next = c; }
 204   Metachunk* next() const         { return _next; }
 205 
 206   DEBUG_ONLY(bool in_list() const { return _prev != NULL || _next != NULL; })
 207 
 208   // Physical neighbors wiring
 209   void set_prev_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _prev_in_vs = c; }
 210   Metachunk* prev_in_vs() const     { DEBUG_ONLY(assert_have_expand_lock()); return _prev_in_vs; }
 211   void set_next_in_vs(Metachunk* c) { DEBUG_ONLY(assert_have_expand_lock()); _next_in_vs = c; }
 212   Metachunk* next_in_vs() const     { DEBUG_ONLY(assert_have_expand_lock()); return _next_in_vs; }
 213 
 214   bool is_free() const            { return _state == state_free; }
 215   bool is_in_use() const          { return _state == state_in_use; }
 216   bool is_dead() const            { return _state == state_dead; }
 217   void set_free()                 { _state = state_free; }
 218   void set_in_use()               { _state = state_in_use; }
 219   void set_dead()                 { _state = state_dead; }
 220 
 221   // Return a single char presentation of the state ('f', 'u', 'd')
 222   char get_state_char() const;
 223 
 224   void inc_level()                { _level ++; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
 225   void dec_level()                { _level --; DEBUG_ONLY(chunklevel::is_valid_level(_level);) }
 226   chunklevel_t level() const          { return _level; }
 227 
 228   // Convenience functions for extreme levels.
 229   bool is_root_chunk() const      { return chunklevel::ROOT_CHUNK_LEVEL == _level; }
 230   bool is_leaf_chunk() const      { return chunklevel::HIGHEST_CHUNK_LEVEL == _level; }
 231 
 232   VirtualSpaceNode* vsnode() const        { return _vsnode; }
 233 
 234   size_t used_words() const                   { return _used_words; }
 235   size_t free_words() const                   { return word_size() - used_words(); }
 236   size_t free_below_committed_words() const   { return committed_words() - used_words(); }
 237   void reset_used_words()                     { _used_words = 0; }
 238 
 239   size_t committed_words() const      { return _committed_words; }
 240   void set_committed_words(size_t v);
 241   bool is_fully_committed() const     { return committed_words() == word_size(); }
 242   bool is_fully_uncommitted() const   { return committed_words() == 0; }
 243 
 244   // Ensure that chunk is committed up to at least new_committed_words words.
 245   // Fails if we hit a commit limit.
 246   bool ensure_committed(size_t new_committed_words);
 247   bool ensure_committed_locked(size_t new_committed_words);
 248 
 249   bool ensure_fully_committed()           { return ensure_committed(word_size()); }
 250   bool ensure_fully_committed_locked()    { return ensure_committed_locked(word_size()); }
 251 
 252   // Ensure that the chunk is committed far enough to serve an additional allocation of word_size.
 253   bool ensure_committed_additional(size_t additional_word_size)   {
 254     return ensure_committed(used_words() + additional_word_size);
 255   }
 256 
 257   // Uncommit chunk area. The area must be a common multiple of the
 258   // commit granule size (in other words, we cannot uncommit chunks smaller than
 259   // a commit granule size).
 260   void uncommit();
 261   void uncommit_locked();
 262 
 263   // Allocation from a chunk
 264 
 265   // Allocate word_size words from this chunk (word_size must be aligned to
 266   //  allocation_alignment_words).
 267   //
 268   // Caller must make sure the chunk is both large enough and committed far enough
 269   // to hold the allocation. Will always work.
 270   //
 271   MetaWord* allocate(size_t request_word_size);
 272 
 273   // Initialize structure for reuse.
 274   void initialize(VirtualSpaceNode* node, MetaWord* base, chunklevel_t lvl) {
 275     _vsnode = node; _base = base; _level = lvl;
 276     _used_words = _committed_words = 0; _state = state_free;
 277     _next = _prev = _next_in_vs = _prev_in_vs = NULL;
 278   }
 279 
 280   // Returns true if this chunk is the leader in its buddy pair, false if not.
 281   // Do not call for root chunks.
 282   bool is_leader() const {
 283     assert(!is_root_chunk(), "Root chunks have no buddy."); // Bit harsh?
 284     return is_aligned(base(), chunklevel::word_size_for_level(level() - 1) * BytesPerWord);
 285   }
 286 
 287   //// Debug stuff ////
 288 #ifdef ASSERT
 289   void verify(bool slow) const;
 290   // Verifies linking with neighbors in virtual space. Needs expand lock protection.
 291   void verify_neighborhood() const;
 292   void zap_header(uint8_t c = 0x17);
 293   void fill_with_pattern(MetaWord pattern, size_t word_size);
 294   void check_pattern(MetaWord pattern, size_t word_size);
 295 
 296   // Returns true if given pointer points into the payload area of this chunk.
 297   bool is_valid_pointer(const MetaWord* p) const {
 298     return base() <= p && p < top();
 299   }
 300 
 301   // Returns true if given pointer points into the commmitted payload area of this chunk.
 302   bool is_valid_committed_pointer(const MetaWord* p) const {
 303     return base() <= p && p < committed_top();
 304   }
 305 
 306 #endif // ASSERT



























 307 
 308   void print_on(outputStream* st) const;
 309 















 310 };
 311 
 312 // Little print helpers: since we often print out chunks, here some convenience macros
 313 #define METACHUNK_FORMAT                "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT
 314 #define METACHUNK_FORMAT_ARGS(chunk)    p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level()
 315 
 316 #define METACHUNK_FULL_FORMAT                "@" PTR_FORMAT ", %c, base " PTR_FORMAT ", level " CHKLVL_FORMAT " (" SIZE_FORMAT "), used: " SIZE_FORMAT ", committed: " SIZE_FORMAT ", committed-free: " SIZE_FORMAT
 317 #define METACHUNK_FULL_FORMAT_ARGS(chunk)    p2i(chunk), chunk->get_state_char(), p2i(chunk->base()), chunk->level(), chunk->word_size(), chunk->used_words(), chunk->committed_words(), chunk->free_below_committed_words()




 318 
 319 } // namespace metaspace
 320 
 321 #endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
< prev index next >