1 /* 2 * Copyright (c) 2018, 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 #include "precompiled.hpp" 25 26 #include "logging/log.hpp" 27 #include "logging/logStream.hpp" 28 #include "memory/metaspace/chunkManager.hpp" 29 #include "memory/metaspace/metachunk.hpp" 30 #include "memory/metaspace/metaDebug.hpp" 31 #include "memory/metaspace/metaspaceCommon.hpp" 32 #include "memory/metaspace/metaspaceStatistics.hpp" 33 #include "memory/metaspace/spaceManager.hpp" 34 #include "memory/metaspace/virtualSpaceList.hpp" 35 #include "runtime/atomic.hpp" 36 #include "runtime/init.hpp" 37 #include "services/memoryService.hpp" 38 #include "utilities/align.hpp" 39 #include "utilities/debug.hpp" 40 #include "utilities/globalDefinitions.hpp" 41 42 namespace metaspace { 43 44 // Given a requested allocation size, in words, returns the minimum size, in words, of an allocation from metaspace. 45 // A metaspace allocation must be large enough to hold a Metablock. This is because deallocated allocations 46 // are kept in the block freelist. 47 static size_t get_allocation_word_size(size_t requested_word_size) { 48 49 size_t byte_size = requested_word_size * BytesPerWord; 50 byte_size = MAX2(byte_size, sizeof(Metablock)); 51 byte_size = align_up(byte_size, Metachunk::allocation_alignment_bytes); 52 53 const size_t word_size = byte_size / BytesPerWord; 54 assert(word_size * BytesPerWord == word_size, "Size problem"); 55 56 return word_size; 57 } 58 59 // Given a requested word size, will allocate a chunk large enough to at least fit that 60 // size, but may be larger according to the rules in the ChunkAllocSequence. 61 // Updates counters and adds the chunk to the head of the chunk list. 62 Metachunk* SpaceManager::allocate_chunk_to_fit(size_t requested_word_size) { 63 64 guarantee(requested_word_size < chklvl::MAX_CHUNK_WORD_SIZE, 65 "Requested size too large (" SIZE_FORMAT ").", requested_word_size); 66 67 const chklvl_t min_level = chklvl::level_fitting_word_size(requested_word_size); 68 chklvl_t max_level = _chunk_alloc_sequence->get_next_chunk_level(_num_chunks_total); 69 70 if (max_level < min_level) { 71 max_level = min_level; 72 } 73 74 Metachunk* c = _chunk_manager->get_chunk(min_level, max_level); 75 assert(c != NULL, "Could not get a chunk"); 76 assert(c->level() >= min_level && c->level() <= max_level, "Sanity"); 77 78 _chunks.add(c); 79 _current_chunk = c; 80 81 return c; 82 83 } 84 85 void SpaceManager::create_block_freelist() { 86 assert(_block_freelist == NULL, "Only call once"); 87 _block_freelist = new BlockFreelist(); 88 } 89 90 SpaceManager::SpaceManager(ChunkManager* chunk_manager, const ChunkAllocSequence* alloc_sequence, Mutex* lock) 91 : _lock(lock), 92 _chunk_manager(chunk_manager), 93 _chunk_alloc_sequence(alloc_sequence), 94 _chunks(), 95 _current_chunk(NULL), 96 _block_freelist(NULL) 97 { 98 } 99 100 SpaceManager::~SpaceManager() { 101 102 assert_lock_strong(lock()); 103 104 MutexLocker fcl(MetaspaceExpand_lock, Mutex::_no_safepoint_check_flag); 105 106 // Return all chunks to our chunk manager. 107 // Note: this destroys the _chunks list. 108 Metachunk* c = _chunks.first(); 109 Metachunk* c2 = NULL; 110 while(c) { 111 c2 = c->next(); 112 _chunk_manager->return_chunk(c); 113 c = c2; 114 } 115 116 #ifdef ASSERT 117 EVERY_NTH(VerifyMetaspaceInterval) 118 chunk_manager()->verify(true); 119 END_EVERY_NTH 120 #endif 121 122 delete _block_freelist; 123 124 } 125 126 // The current chunk is unable to service a request. The remainder of the chunk is 127 // chopped into blocks and fed into the _block_freelists, in the hope of later reuse. 128 void SpaceManager::retire_current_chunk() { 129 Metachunk* c = _current_chunk; 130 assert(c != NULL, "Sanity"); 131 assert(c->used_words() > 0, "Why do we retire an empty chunk?"); 132 size_t remaining_words = c->free_below_committed_words(); 133 if (remaining_words >= SmallBlocks::small_block_min_size()) { 134 bool did_hit_limit = false; 135 MetaWord* ptr = c->allocate(remaining_words, &did_hit_limit); 136 assert(ptr != NULL && did_hit_limit == false, "Should have worked"); 137 deallocate(ptr, remaining_words); 138 } 139 } 140 141 // Allocate memory from Metaspace. 142 // 1) Attempt to allocate from the dictionary of deallocated blocks. 143 // 2) Failing that, attempt to allocate from the current chunk. If this 144 // fails because the chunk needed to be committed and we hit a commit limit, return NULL. 145 // 3) Attempt to get a new chunk and allocate from that chunk. Again, we may hit a commit 146 // limit, in which case we return NULL. 147 MetaWord* SpaceManager::allocate(size_t requested_word_size) { 148 149 MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag); 150 151 const size_t word_size = align_up(requested_word_size, get_allocation_word_size(requested_word_size)); 152 153 MetaWord* p = NULL; 154 155 bool did_hit_limit = false; 156 157 // Allocate first chunk if needed. 158 if (_current_chunk == NULL) { 159 Metachunk* c = allocate_chunk_to_fit(requested_word_size); 160 assert(c != NULL && _chunks.size() == 1 && c == _current_chunk, "Should be"); 161 } 162 163 // 1) Attempt to allocate from the dictionary of deallocated blocks. 164 165 // Allocation from the dictionary is expensive in the sense that 166 // the dictionary has to be searched for a size. Don't allocate 167 // from the dictionary until it starts to get fat. Is this 168 // a reasonable policy? Maybe an skinny dictionary is fast enough 169 // for allocations. Do some profiling. JJJ 170 if (_block_freelist != NULL && _block_freelist->total_size() > constants::allocation_from_dictionary_limit) { 171 p = _block_freelist->get_block(requested_word_size); 172 if (p != NULL) { 173 DEBUG_ONLY(Atomic::inc(&g_internal_statistics.num_allocs_from_deallocated_blocks)); 174 } 175 } 176 177 // 2) Attempt to allocate from the current chunk. 178 if (p == NULL && !did_hit_limit) { 179 p = _current_chunk->allocate(requested_word_size, &did_hit_limit); 180 } 181 182 // 3) Attempt to get a new chunk and allocate from that chunk. 183 if (p == NULL && !did_hit_limit) { 184 185 // Old chunk is too small to hold requested size? 186 assert(_current_chunk->free_words() < requested_word_size, "Sanity"); 187 188 // Retire the old chunk. This will put all remainder space (committed 189 // space only) into the block freelist. 190 retire_current_chunk(); 191 assert(_current_chunk->free_below_committed_words() == 0, "Sanity"); 192 193 // Allocate a new chunk. 194 Metachunk* c = allocate_chunk_to_fit(requested_word_size); 195 assert(c != NULL && _chunks.size() > 0 && c == _current_chunk, "Should be"); 196 197 p = _current_chunk->allocate(requested_word_size, &did_hit_limit); 198 199 } 200 201 assert(p != NULL || (p == NULL && did_hit_limit), "Sanity"); 202 203 return p; 204 205 } 206 207 208 // Update statistics. This walks all in-use chunks. 209 void SpaceManager::add_to_statistics(SpaceManagerStatistics* out) const { 210 211 for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) { 212 UsedChunksStatistics& ucs = out->chunk_stats[c->level()]; 213 ucs.cap += c->word_size(); 214 // Note: for free and waste, we only count what's committed. 215 if (c == _current_chunk) { 216 ucs.free += c->free_words(); 217 } else { 218 ucs.waste += c->free_words(); 219 } 220 221 } 222 223 if (block_freelist() != NULL) { 224 out->add_free_blocks_info(block_freelist()->num_blocks(), block_freelist()->total_size()); 225 } 226 227 } 228 229 } // namespace metaspace 230