rev 57625 : [mq]: metaspace-improvement
1 /* 2 * Copyright (c) 2012, 2016, 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 25 26 #include "precompiled.hpp" 27 28 #include "logging/log.hpp" 29 #include "memory/metaspace/chunkLevel.hpp" 30 #include "memory/metaspace/constants.hpp" 31 #include "memory/metaspace/metachunk.hpp" 32 #include "memory/metaspace/metaspaceCommon.hpp" 33 #include "memory/metaspace/virtualSpaceNode.hpp" 34 35 #include "utilities/align.hpp" 36 #include "utilities/copy.hpp" 37 #include "utilities/debug.hpp" 38 39 namespace metaspace { 40 41 // Make sure that the Klass alignment also agree. 42 STATIC_ASSERT(Metachunk::allocation_alignment_bytes == (size_t)KlassAlignmentInBytes); 43 44 void Metachunk::remove_from_list() { 45 if (_prev != NULL) { 46 _prev->set_next(_next); 47 } 48 if (_next != NULL) { 49 _next->set_prev(_prev); 50 } 51 _prev = _next = NULL; 52 } 53 54 55 // Commit uncommitted section of the chunk. 56 // Fails if we hit a commit limit. 57 bool Metachunk::commit_up_to(size_t new_committed_words) { 58 59 // We should hold the expand lock at this point. 60 assert_lock_strong(MetaspaceExpand_lock); 61 62 assert(new_committed_words <= word_size(), "Sanity."); 63 64 // Note: we may commit more than the area of our own chunk and that is okay. 65 MetaWord* const commit_top = align_down(base() + committed_words(), constants::commit_granule_words); 66 MetaWord* const new_commit_top = align_up(base() + new_committed_words, constants::commit_granule_words); 67 68 // Function should only be called if there is someting to commit. 69 assert(new_commit_top > commit_top, "No need to commit."); 70 71 log_debug(metaspace)("Chunk " PTR_FORMAT ": attempting to move commit line to " 72 SIZE_FORMAT " words.", p2i(this), new_committed_words); 73 74 if (!_vsnode->ensure_range_is_committed(commit_top, new_commit_top - commit_top)) { 75 return false; 76 } 77 78 // Remember how far we have committed. 79 _committed_words = new_commit_top - base(); 80 if (_committed_words > word_size()) { 81 _committed_words = word_size(); 82 } 83 84 return true; 85 86 } 87 88 89 // Ensure that chunk is committed up to at least new_committed_words words. 90 // Fails if we hit a commit limit. 91 bool Metachunk::ensure_committed(size_t new_committed_words) { 92 93 bool rc = true; 94 95 if (new_committed_words > committed_words()) { 96 MutexLocker cl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); 97 rc = commit_up_to(new_committed_words); 98 } 99 100 return rc; 101 102 } 103 104 bool Metachunk::ensure_committed_locked(size_t new_committed_words) { 105 106 // the .._locked() variant should be called if we own the lock already. 107 assert_lock_strong(MetaspaceExpand_lock); 108 109 bool rc = true; 110 111 if (new_committed_words > committed_words()) { 112 rc = commit_up_to(new_committed_words); 113 } 114 115 return rc; 116 117 } 118 119 // Allocate word_size words from this chunk. 120 // 121 // May cause memory to be committed. That may fail if we hit a commit limit. In that case, 122 // NULL is returned and p_did_hit_commit_limit will be set to true. 123 // If the remainder portion of the chunk was too small to hold the allocation, 124 // NULL is returned and p_did_hit_commit_limit will be set to false. 125 MetaWord* Metachunk::allocate(size_t word_size, bool* p_did_hit_commit_limit) { 126 127 size_t request_word_size = align_up(word_size, allocation_alignment_words); 128 129 log_trace(metaspace)("Chunk " PTR_FORMAT ": allocating " 130 SIZE_FORMAT " words.", p2i(this), word_size); 131 132 // Space enough left? 133 if (free_words() < request_word_size) { 134 *p_did_hit_commit_limit = false; 135 log_trace(metaspace)("Chunk " PTR_FORMAT ": .. does not fit (remaining space: " 136 SIZE_FORMAT " words).", p2i(this), free_words()); 137 return NULL; 138 } 139 140 // Expand committed region if necessary. 141 if (ensure_committed(used_words() + request_word_size) == false) { 142 *p_did_hit_commit_limit = true; 143 log_trace(metaspace)("Chunk " PTR_FORMAT ": .. failed, we hit a limit.", p2i(this)); 144 return NULL; 145 } 146 147 MetaWord* const p = top(); 148 149 _used_words += request_word_size; 150 151 return p; 152 153 } 154 155 #ifdef ASSERT 156 157 void Metachunk::verify(bool slow) const { 158 159 // Note: only call this on a life Metachunk. 160 chklvl::check_valid_level(level()); 161 162 assert(base() != NULL, "No base ptr"); 163 assert(committed_words() >= used_words(), "Sanity"); 164 assert(word_size() >= committed_words(), "Sanity"); 165 166 // Test base pointer 167 assert(vsnode() != NULL, "No space"); 168 vsnode()->check_pointer(base()); 169 assert(base() != NULL, "Base pointer NULL"); 170 171 // Starting address shall be aligned to chunk size. 172 const size_t required_alignment = word_size() * sizeof(MetaWord); 173 assert_is_aligned(base(), required_alignment); 174 175 // Used words 176 assert(used_words() < word_size(), "oob"); 177 178 // If we are not a root chunk, we shall have a reference to a tree node 179 assert(tree_node_ref() != 0 || level() == chklvl::ROOT_CHUNK_LEVEL, "No parent node."); 180 181 } 182 #endif // ASSERT 183 184 185 #ifdef ASSERT 186 187 bool MetachunkList::contains(const Metachunk* c) const { 188 for (Metachunk* c2 = first(); c2 != NULL; c2 = c2->next()) { 189 if (c == c2) { 190 return true; 191 } 192 } 193 return false; 194 } 195 196 void MetachunkList::verify(bool slow) const { 197 int num = 0; 198 for (Metachunk* c = first(); c != NULL; c = c->next()) { 199 num ++; 200 if (slow) { 201 c->verify(false); 202 } 203 _num.check(num); 204 } 205 } 206 207 #endif // ASSERT 208 209 } // namespace metaspace 210 --- EOF ---