rev 57625 : [mq]: metaspace-improvement
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 28 #include "memory/metaspace/counter.hpp" 29 #include "memory/metaspace/abstractPool.hpp" 30 #include "memory/metaspace/chunkLevel.hpp" 31 #include "utilities/debug.hpp" 32 #include "utilities/globalDefinitions.hpp" 33 34 35 36 namespace metaspace { 37 38 class VirtualSpaceNode; 39 40 // Metachunk - Quantum of allocation from a Virtualspace 41 // Metachunks are reused (when freed are put on a global freelist) and 42 // have no permanent association to a SpaceManager. 43 44 // +--------------+ <- end ----+ --+ 45 // | | | | 46 // | | | free | 47 // | | | 48 // | | | | size (aka capacity) 49 // | | | | 50 // | ----------- | <- top -- + | 51 // | | | | 52 // | | | used | 53 // +--------------+ <- start -- + -- + 54 55 // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace, 56 // this class lives somewhere else. 57 class Metachunk { 58 59 // Todo: compact this node. A lot of things can be expressed more tighter. 60 61 // A chunk header is kept in a list: 62 // - in the list of used chunks inside a SpaceManager, if it is in use 63 // - in the list of free chunks inside a ChunkManager, if it is free 64 // - in the freelist of dead headers inside the MetaChunkHeaderPool, 65 // if it is dead (e.g. result of chunk merging). 66 Metachunk* _prev; 67 Metachunk* _next; 68 69 chklvl_t _level; // aka size. 70 71 // true: free, owned by ChunkManager 72 // false: in-use, owned by SpaceManager 73 // if dead, meaningless 74 bool _is_free; 75 76 // start of chunk memory; NULL if dead. 77 MetaWord* _base; 78 79 // Used words. 80 size_t _used_words; 81 82 // Guaranteed-to-be-committed-words, counted from base 83 // (This is a performance optimization. The underlying VirtualSpaceNode knows 84 // which granules are committed; but we want to avoid asking it unnecessarily 85 // in Metachunk::allocate(), so we keep a limit until which we are guaranteed 86 // to have committed memory under us.) 87 size_t _committed_words; 88 89 // the chunk tree node this header is hanging under; NULL if dead. 90 u2 _tree_node_ref; 91 92 // We need unfortunately a back link to the virtual space node 93 // for splitting and merging nodes. 94 VirtualSpaceNode* _vsnode; 95 96 MetaWord* top() const { return base() + _used_words; } 97 98 // Commit uncommitted section of the chunk. 99 // Fails if we hit a commit limit. 100 bool commit_up_to(size_t new_committed_words); 101 102 public: 103 104 Metachunk() 105 : _prev(NULL), _next(NULL), 106 _level(chklvl::ROOT_CHUNK_LEVEL), 107 _is_free(true), 108 _base(NULL), 109 _used_words(0), 110 _committed_words(0), 111 _tree_node_ref(0), 112 _vsnode(NULL) 113 {} 114 115 size_t word_size() const { return chklvl::word_size_for_level(_level); } 116 117 MetaWord* base() const { return _base; } 118 void set_base(MetaWord* p) { _base = p; } 119 MetaWord* end() const { return base() + word_size(); } 120 121 void set_prev(Metachunk* c) { _prev = c; } 122 Metachunk* prev() const { return _prev; } 123 void set_next(Metachunk* c) { _next = c; } 124 Metachunk* next() const { return _next; } 125 // Remove chunk from whatever list it lives in by wiring next with previous. 126 void remove_from_list(); 127 128 bool is_free() const { return _is_free; } 129 bool is_in_use() const { return !_is_free; } 130 void set_free(bool v) { _is_free = v; } 131 132 133 void inc_level() { _level ++; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 134 void dec_level() { _level --; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 135 void set_level(chklvl_t v) { _level = v; DEBUG_ONLY(chklvl::is_valid_level(_level);) } 136 chklvl_t level() const { return _level; } 137 138 void set_tree_node_ref(u2 v) { _tree_node_ref = v; } 139 u2 tree_node_ref() const { return _tree_node_ref; } 140 141 VirtualSpaceNode* vsnode() const { return _vsnode; } 142 void set_vsnode(VirtualSpaceNode* n) { _vsnode = n; } 143 144 size_t used_words() const { return _used_words; } 145 size_t free_words() const { return word_size() - used_words(); } 146 size_t free_below_committed_words() const { return committed_words() - used_words(); } 147 void reset_used_words() { _used_words = 0; } 148 149 size_t committed_words() const { return _committed_words; } 150 void set_committed_words(size_t v) { _committed_words = v; } 151 bool is_fully_committed() const { return committed_words() == word_size(); } 152 153 // Ensure that chunk is committed up to at least new_committed_words words. 154 // Fails if we hit a commit limit. 155 bool ensure_committed(size_t new_committed_words); 156 bool ensure_committed_locked(size_t new_committed_words); 157 158 // Alignment of an allocation. 159 static const size_t allocation_alignment_bytes = 8; 160 static const size_t allocation_alignment_words = allocation_alignment_bytes / BytesPerWord; 161 162 // Allocation from a chunk 163 164 // Allocate word_size words from this chunk. 165 // 166 // May cause memory to be committed. That may fail if we hit a commit limit. In that case, 167 // NULL is returned and p_did_hit_commit_limit will be set to true. 168 // If the remainder portion of the chunk was too small to hold the allocation, 169 // NULL is returned and p_did_hit_commit_limit will be set to false. 170 MetaWord* allocate(size_t word_size, bool* p_did_hit_commit_limit); 171 172 // Wipe this object to look as if it were default constructed. 173 void wipe() { 174 _prev = NULL; _next = NULL; 175 _level = chklvl::ROOT_CHUNK_LEVEL; 176 _is_free = true; 177 _base = NULL; 178 _used_words = 0; 179 _committed_words = 0; 180 _tree_node_ref = 0; 181 _vsnode = NULL; 182 } 183 184 //// Debug stuff //// 185 DEBUG_ONLY(void verify(bool slow) const;) 186 187 }; 188 189 190 class MetachunkList { 191 192 Metachunk* _first; 193 IntCounter _num; 194 195 public: 196 197 MetachunkList() : _first(NULL), _num() {} 198 199 Metachunk* first() const { return _first; } 200 int size() const { return _num.get(); } 201 202 void add(Metachunk* c) { 203 c->set_next(_first); 204 _first = c; 205 _num.increment(); 206 } 207 208 // Remove first node unless empty. Returns node or NULL. 209 Metachunk* remove_first() { 210 Metachunk* c = _first; 211 if (c != NULL) { 212 _first = c->next(); 213 _num.decrement(); 214 } 215 return c; 216 } 217 218 // Remove given chunk from list. List must contain that chunk. 219 void remove(Metachunk* c) { 220 assert(contains(c), "Does not contain this chunk"); 221 c->remove_from_list(); 222 _num.decrement(); 223 } 224 225 // Manually decrement counter; needed for cases where chunks 226 // have been manually removed from the list without informing 227 // the list, e.g. chunk merging, see chunkManager::return_chunk(). 228 void dec_counter_by(int v) { 229 _num.decrement_by(v); 230 } 231 232 #ifdef ASSERT 233 bool contains(const Metachunk* c) const; 234 void verify(bool slow) const; 235 #endif 236 237 }; 238 239 } // namespace metaspace 240 241 #endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP --- EOF ---