1.1 --- a/src/share/vm/memory/metaspace.cpp Wed Sep 20 20:54:29 2017 -0400 1.2 +++ b/src/share/vm/memory/metaspace.cpp Mon Dec 11 02:39:24 2017 -0800 1.3 @@ -531,9 +531,8 @@ 1.4 1.5 size_t free_bytes(); 1.6 1.7 - Metachunk* get_new_chunk(size_t word_size, 1.8 - size_t grow_chunks_by_words, 1.9 - size_t medium_chunk_bunch); 1.10 + Metachunk* get_new_chunk(size_t chunk_word_size, 1.11 + size_t suggested_commit_granularity); 1.12 1.13 bool expand_node_by(VirtualSpaceNode* node, 1.14 size_t min_words, 1.15 @@ -687,15 +686,22 @@ 1.16 MediumChunkMultiple = 4 1.17 }; 1.18 1.19 - bool is_class() { return _mdtype == Metaspace::ClassType; } 1.20 + static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; } 1.21 + static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; } 1.22 + static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; } 1.23 + 1.24 + static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); } 1.25 1.26 // Accessors 1.27 - size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } 1.28 - size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } 1.29 - size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } 1.30 - size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } 1.31 - 1.32 - size_t smallest_chunk_size() { return specialized_chunk_size(); } 1.33 + bool is_class() const { return _mdtype == Metaspace::ClassType; } 1.34 + 1.35 + size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); } 1.36 + size_t small_chunk_size() const { return small_chunk_size(is_class()); } 1.37 + size_t medium_chunk_size() const { return medium_chunk_size(is_class()); } 1.38 + 1.39 + size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); } 1.40 + 1.41 + size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; } 1.42 1.43 size_t allocated_blocks_words() const { return _allocated_blocks_words; } 1.44 size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } 1.45 @@ -718,10 +724,13 @@ 1.46 // decremented for all the Metachunks in-use by this SpaceManager. 1.47 void dec_total_from_size_metrics(); 1.48 1.49 - // Set the sizes for the initial chunks. 1.50 - void get_initial_chunk_sizes(Metaspace::MetaspaceType type, 1.51 - size_t* chunk_word_size, 1.52 - size_t* class_chunk_word_size); 1.53 + // Adjust the initial chunk size to match one of the fixed chunk list sizes, 1.54 + // or return the unadjusted size if the requested size is humongous. 1.55 + static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space); 1.56 + size_t adjust_initial_chunk_size(size_t requested) const; 1.57 + 1.58 + // Get the initial chunks size for this metaspace type. 1.59 + size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const; 1.60 1.61 size_t sum_capacity_in_chunks_in_use() const; 1.62 size_t sum_used_in_chunks_in_use() const; 1.63 @@ -732,7 +741,7 @@ 1.64 size_t sum_count_in_chunks_in_use(); 1.65 size_t sum_count_in_chunks_in_use(ChunkIndex i); 1.66 1.67 - Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words); 1.68 + Metachunk* get_new_chunk(size_t chunk_word_size); 1.69 1.70 // Block allocation and deallocation. 1.71 // Allocates a block from the current chunk 1.72 @@ -1319,12 +1328,10 @@ 1.73 return false; 1.74 } 1.75 1.76 -Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, 1.77 - size_t grow_chunks_by_words, 1.78 - size_t medium_chunk_bunch) { 1.79 +Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) { 1.80 1.81 // Allocate a chunk out of the current virtual space. 1.82 - Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); 1.83 + Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size); 1.84 1.85 if (next != NULL) { 1.86 return next; 1.87 @@ -1333,8 +1340,8 @@ 1.88 // The expand amount is currently only determined by the requested sizes 1.89 // and not how much committed memory is left in the current virtual space. 1.90 1.91 - size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words()); 1.92 - size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words()); 1.93 + size_t min_word_size = align_size_up(chunk_word_size, Metaspace::commit_alignment_words()); 1.94 + size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words()); 1.95 if (min_word_size >= preferred_word_size) { 1.96 // Can happen when humongous chunks are allocated. 1.97 preferred_word_size = min_word_size; 1.98 @@ -1342,7 +1349,7 @@ 1.99 1.100 bool expanded = expand_by(min_word_size, preferred_word_size); 1.101 if (expanded) { 1.102 - next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); 1.103 + next = current_virtual_space()->get_chunk_vs(chunk_word_size); 1.104 assert(next != NULL, "The allocation was expected to succeed after the expansion"); 1.105 } 1.106 1.107 @@ -1883,36 +1890,58 @@ 1.108 1.109 // SpaceManager methods 1.110 1.111 -void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, 1.112 - size_t* chunk_word_size, 1.113 - size_t* class_chunk_word_size) { 1.114 - switch (type) { 1.115 - case Metaspace::BootMetaspaceType: 1.116 - *chunk_word_size = Metaspace::first_chunk_word_size(); 1.117 - *class_chunk_word_size = Metaspace::first_class_chunk_word_size(); 1.118 - break; 1.119 - case Metaspace::ROMetaspaceType: 1.120 - *chunk_word_size = SharedReadOnlySize / wordSize; 1.121 - *class_chunk_word_size = ClassSpecializedChunk; 1.122 - break; 1.123 - case Metaspace::ReadWriteMetaspaceType: 1.124 - *chunk_word_size = SharedReadWriteSize / wordSize; 1.125 - *class_chunk_word_size = ClassSpecializedChunk; 1.126 - break; 1.127 - case Metaspace::AnonymousMetaspaceType: 1.128 - case Metaspace::ReflectionMetaspaceType: 1.129 - *chunk_word_size = SpecializedChunk; 1.130 - *class_chunk_word_size = ClassSpecializedChunk; 1.131 - break; 1.132 - default: 1.133 - *chunk_word_size = SmallChunk; 1.134 - *class_chunk_word_size = ClassSmallChunk; 1.135 - break; 1.136 +size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) { 1.137 + size_t chunk_sizes[] = { 1.138 + specialized_chunk_size(is_class_space), 1.139 + small_chunk_size(is_class_space), 1.140 + medium_chunk_size(is_class_space) 1.141 + }; 1.142 + 1.143 + // Adjust up to one of the fixed chunk sizes ... 1.144 + for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) { 1.145 + if (requested <= chunk_sizes[i]) { 1.146 + return chunk_sizes[i]; 1.147 + } 1.148 } 1.149 - assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, 1.150 - err_msg("Initial chunks sizes bad: data " SIZE_FORMAT 1.151 - " class " SIZE_FORMAT, 1.152 - *chunk_word_size, *class_chunk_word_size)); 1.153 + 1.154 + // ... or return the size as a humongous chunk. 1.155 + return requested; 1.156 +} 1.157 + 1.158 +size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const { 1.159 + return adjust_initial_chunk_size(requested, is_class()); 1.160 +} 1.161 + 1.162 +size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const { 1.163 + size_t requested; 1.164 + 1.165 + if (is_class()) { 1.166 + switch (type) { 1.167 + case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break; 1.168 + case Metaspace::ROMetaspaceType: requested = ClassSpecializedChunk; break; 1.169 + case Metaspace::ReadWriteMetaspaceType: requested = ClassSpecializedChunk; break; 1.170 + case Metaspace::AnonymousMetaspaceType: requested = ClassSpecializedChunk; break; 1.171 + case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break; 1.172 + default: requested = ClassSmallChunk; break; 1.173 + } 1.174 + } else { 1.175 + switch (type) { 1.176 + case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break; 1.177 + case Metaspace::ROMetaspaceType: requested = SharedReadOnlySize / wordSize; break; 1.178 + case Metaspace::ReadWriteMetaspaceType: requested = SharedReadWriteSize / wordSize; break; 1.179 + case Metaspace::AnonymousMetaspaceType: requested = SpecializedChunk; break; 1.180 + case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break; 1.181 + default: requested = SmallChunk; break; 1.182 + } 1.183 + } 1.184 + 1.185 + // Adjust to one of the fixed chunk sizes (unless humongous) 1.186 + const size_t adjusted = adjust_initial_chunk_size(requested); 1.187 + 1.188 + assert(adjusted != 0, err_msg("Incorrect initial chunk size. Requested: " 1.189 + SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted)); 1.190 + 1.191 + return adjusted; 1.192 } 1.193 1.194 size_t SpaceManager::sum_free_in_chunks_in_use() const { 1.195 @@ -2102,8 +2131,8 @@ 1.196 } 1.197 1.198 // Get another chunk out of the virtual space 1.199 - size_t grow_chunks_by_words = calc_chunk_size(word_size); 1.200 - Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); 1.201 + size_t chunk_word_size = calc_chunk_size(word_size); 1.202 + Metachunk* next = get_new_chunk(chunk_word_size); 1.203 1.204 MetaWord* mem = NULL; 1.205 1.206 @@ -2412,14 +2441,12 @@ 1.207 } 1.208 } 1.209 1.210 -Metachunk* SpaceManager::get_new_chunk(size_t word_size, 1.211 - size_t grow_chunks_by_words) { 1.212 +Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) { 1.213 // Get a chunk from the chunk freelist 1.214 - Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); 1.215 + Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size); 1.216 1.217 if (next == NULL) { 1.218 - next = vs_list()->get_new_chunk(word_size, 1.219 - grow_chunks_by_words, 1.220 + next = vs_list()->get_new_chunk(chunk_word_size, 1.221 medium_chunk_bunch()); 1.222 } 1.223 1.224 @@ -3085,7 +3112,7 @@ 1.225 err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize)); 1.226 assert(using_class_space(), "Must be using class space"); 1.227 _class_space_list = new VirtualSpaceList(rs); 1.228 - _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); 1.229 + _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk); 1.230 1.231 if (!_class_space_list->initialization_succeeded()) { 1.232 vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); 1.233 @@ -3286,66 +3313,62 @@ 1.234 MetaspaceGC::post_initialize(); 1.235 } 1.236 1.237 -Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, 1.238 - size_t chunk_word_size, 1.239 - size_t chunk_bunch) { 1.240 +void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) { 1.241 + Metachunk* chunk = get_initialization_chunk(type, mdtype); 1.242 + if (chunk != NULL) { 1.243 + // Add to this manager's list of chunks in use and current_chunk(). 1.244 + get_space_manager(mdtype)->add_chunk(chunk, true); 1.245 + } 1.246 +} 1.247 + 1.248 +Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) { 1.249 + size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type); 1.250 + 1.251 // Get a chunk from the chunk freelist 1.252 Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size); 1.253 - if (chunk != NULL) { 1.254 - return chunk; 1.255 + 1.256 + if (chunk == NULL) { 1.257 + chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size, 1.258 + get_space_manager(mdtype)->medium_chunk_bunch()); 1.259 } 1.260 1.261 - return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch); 1.262 + // For dumping shared archive, report error if allocation has failed. 1.263 + if (DumpSharedSpaces && chunk == NULL) { 1.264 + report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord); 1.265 + } 1.266 + 1.267 + return chunk; 1.268 } 1.269 1.270 +void Metaspace::verify_global_initialization() { 1.271 + assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized"); 1.272 + assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized"); 1.273 + 1.274 + if (using_class_space()) { 1.275 + assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized"); 1.276 + assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized"); 1.277 + } 1.278 +} 1.279 + 1.280 void Metaspace::initialize(Mutex* lock, MetaspaceType type) { 1.281 - 1.282 - assert(space_list() != NULL, 1.283 - "Metadata VirtualSpaceList has not been initialized"); 1.284 - assert(chunk_manager_metadata() != NULL, 1.285 - "Metadata ChunkManager has not been initialized"); 1.286 - 1.287 + verify_global_initialization(); 1.288 + 1.289 + // Allocate SpaceManager for metadata objects. 1.290 _vsm = new SpaceManager(NonClassType, lock); 1.291 - if (_vsm == NULL) { 1.292 - return; 1.293 - } 1.294 - size_t word_size; 1.295 - size_t class_word_size; 1.296 - vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size); 1.297 1.298 if (using_class_space()) { 1.299 - assert(class_space_list() != NULL, 1.300 - "Class VirtualSpaceList has not been initialized"); 1.301 - assert(chunk_manager_class() != NULL, 1.302 - "Class ChunkManager has not been initialized"); 1.303 - 1.304 // Allocate SpaceManager for classes. 1.305 _class_vsm = new SpaceManager(ClassType, lock); 1.306 - if (_class_vsm == NULL) { 1.307 - return; 1.308 - } 1.309 } 1.310 1.311 MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); 1.312 1.313 // Allocate chunk for metadata objects 1.314 - Metachunk* new_chunk = get_initialization_chunk(NonClassType, 1.315 - word_size, 1.316 - vsm()->medium_chunk_bunch()); 1.317 - assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks"); 1.318 - if (new_chunk != NULL) { 1.319 - // Add to this manager's list of chunks in use and current_chunk(). 1.320 - vsm()->add_chunk(new_chunk, true); 1.321 - } 1.322 + initialize_first_chunk(type, NonClassType); 1.323 1.324 // Allocate chunk for class metadata objects 1.325 if (using_class_space()) { 1.326 - Metachunk* class_chunk = get_initialization_chunk(ClassType, 1.327 - class_word_size, 1.328 - class_vsm()->medium_chunk_bunch()); 1.329 - if (class_chunk != NULL) { 1.330 - class_vsm()->add_chunk(class_chunk, true); 1.331 - } 1.332 + initialize_first_chunk(type, ClassType); 1.333 } 1.334 1.335 _alloc_record_head = NULL; 1.336 @@ -3772,7 +3795,7 @@ 1.337 // vm_allocation_granularity aligned on Windows. 1.338 size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord)); 1.339 large_size += (os::vm_page_size()/BytesPerWord); 1.340 - vs_list->get_new_chunk(large_size, large_size, 0); 1.341 + vs_list->get_new_chunk(large_size, 0); 1.342 } 1.343 1.344 static void test() { 1.345 @@ -3947,4 +3970,54 @@ 1.346 TestVirtualSpaceNodeTest::test(); 1.347 TestVirtualSpaceNodeTest::test_is_available(); 1.348 } 1.349 + 1.350 +// The following test is placed here instead of a gtest / unittest file 1.351 +// because the ChunkManager class is only available in this file. 1.352 +class SpaceManagerTest : AllStatic { 1.353 + friend void SpaceManager_test_adjust_initial_chunk_size(); 1.354 + 1.355 + static void test_adjust_initial_chunk_size(bool is_class) { 1.356 + const size_t smallest = SpaceManager::smallest_chunk_size(is_class); 1.357 + const size_t normal = SpaceManager::small_chunk_size(is_class); 1.358 + const size_t medium = SpaceManager::medium_chunk_size(is_class); 1.359 + 1.360 +#define test_adjust_initial_chunk_size(value, expected, is_class_value) \ 1.361 + do { \ 1.362 + size_t v = value; \ 1.363 + size_t e = expected; \ 1.364 + assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e, \ 1.365 + err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v)); \ 1.366 + } while (0) 1.367 + 1.368 + // Smallest (specialized) 1.369 + test_adjust_initial_chunk_size(1, smallest, is_class); 1.370 + test_adjust_initial_chunk_size(smallest - 1, smallest, is_class); 1.371 + test_adjust_initial_chunk_size(smallest, smallest, is_class); 1.372 + 1.373 + // Small 1.374 + test_adjust_initial_chunk_size(smallest + 1, normal, is_class); 1.375 + test_adjust_initial_chunk_size(normal - 1, normal, is_class); 1.376 + test_adjust_initial_chunk_size(normal, normal, is_class); 1.377 + 1.378 + // Medium 1.379 + test_adjust_initial_chunk_size(normal + 1, medium, is_class); 1.380 + test_adjust_initial_chunk_size(medium - 1, medium, is_class); 1.381 + test_adjust_initial_chunk_size(medium, medium, is_class); 1.382 + 1.383 + // Humongous 1.384 + test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class); 1.385 + 1.386 +#undef test_adjust_initial_chunk_size 1.387 + } 1.388 + 1.389 + static void test_adjust_initial_chunk_size() { 1.390 + test_adjust_initial_chunk_size(false); 1.391 + test_adjust_initial_chunk_size(true); 1.392 + } 1.393 +}; 1.394 + 1.395 +void SpaceManager_test_adjust_initial_chunk_size() { 1.396 + SpaceManagerTest::test_adjust_initial_chunk_size(); 1.397 +} 1.398 + 1.399 #endif