< prev index next >

src/share/vm/memory/metaspace.cpp

Print this page

        

*** 529,541 **** VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); size_t free_bytes(); ! Metachunk* get_new_chunk(size_t word_size, ! size_t grow_chunks_by_words, ! size_t medium_chunk_bunch); bool expand_node_by(VirtualSpaceNode* node, size_t min_words, size_t preferred_words); --- 529,540 ---- VirtualSpaceList(size_t word_size); VirtualSpaceList(ReservedSpace rs); size_t free_bytes(); ! Metachunk* get_new_chunk(size_t chunk_word_size, ! size_t suggested_commit_granularity); bool expand_node_by(VirtualSpaceNode* node, size_t min_words, size_t preferred_words);
*** 685,703 **** enum ChunkMultiples { MediumChunkMultiple = 4 }; ! bool is_class() { return _mdtype == Metaspace::ClassType; } // Accessors ! size_t specialized_chunk_size() { return (size_t) is_class() ? ClassSpecializedChunk : SpecializedChunk; } ! size_t small_chunk_size() { return (size_t) is_class() ? ClassSmallChunk : SmallChunk; } ! size_t medium_chunk_size() { return (size_t) is_class() ? ClassMediumChunk : MediumChunk; } ! size_t medium_chunk_bunch() { return medium_chunk_size() * MediumChunkMultiple; } ! size_t smallest_chunk_size() { return specialized_chunk_size(); } size_t allocated_blocks_words() const { return _allocated_blocks_words; } size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } size_t allocated_chunks_words() const { return _allocated_chunks_words; } size_t allocated_chunks_count() const { return _allocated_chunks_count; } --- 684,709 ---- enum ChunkMultiples { MediumChunkMultiple = 4 }; ! static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; } ! static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; } ! static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; } ! ! static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); } // Accessors ! bool is_class() const { return _mdtype == Metaspace::ClassType; } ! ! size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); } ! size_t small_chunk_size() const { return small_chunk_size(is_class()); } ! size_t medium_chunk_size() const { return medium_chunk_size(is_class()); } ! size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); } ! ! size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; } size_t allocated_blocks_words() const { return _allocated_blocks_words; } size_t allocated_blocks_bytes() const { return _allocated_blocks_words * BytesPerWord; } size_t allocated_chunks_words() const { return _allocated_chunks_words; } size_t allocated_chunks_count() const { return _allocated_chunks_count; }
*** 716,740 **** // Delete the portion of the running sums for this SpaceManager. That is, // the globals running sums for the Metachunks and Metablocks are // decremented for all the Metachunks in-use by this SpaceManager. void dec_total_from_size_metrics(); ! // Set the sizes for the initial chunks. ! void get_initial_chunk_sizes(Metaspace::MetaspaceType type, ! size_t* chunk_word_size, ! size_t* class_chunk_word_size); size_t sum_capacity_in_chunks_in_use() const; size_t sum_used_in_chunks_in_use() const; size_t sum_free_in_chunks_in_use() const; size_t sum_waste_in_chunks_in_use() const; size_t sum_waste_in_chunks_in_use(ChunkIndex index ) const; size_t sum_count_in_chunks_in_use(); size_t sum_count_in_chunks_in_use(ChunkIndex i); ! Metachunk* get_new_chunk(size_t word_size, size_t grow_chunks_by_words); // Block allocation and deallocation. // Allocates a block from the current chunk MetaWord* allocate(size_t word_size); --- 722,749 ---- // Delete the portion of the running sums for this SpaceManager. That is, // the globals running sums for the Metachunks and Metablocks are // decremented for all the Metachunks in-use by this SpaceManager. void dec_total_from_size_metrics(); ! // Adjust the initial chunk size to match one of the fixed chunk list sizes, ! // or return the unadjusted size if the requested size is humongous. ! static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space); ! size_t adjust_initial_chunk_size(size_t requested) const; ! ! // Get the initial chunks size for this metaspace type. ! size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const; size_t sum_capacity_in_chunks_in_use() const; size_t sum_used_in_chunks_in_use() const; size_t sum_free_in_chunks_in_use() const; size_t sum_waste_in_chunks_in_use() const; size_t sum_waste_in_chunks_in_use(ChunkIndex index ) const; size_t sum_count_in_chunks_in_use(); size_t sum_count_in_chunks_in_use(ChunkIndex i); ! Metachunk* get_new_chunk(size_t chunk_word_size); // Block allocation and deallocation. // Allocates a block from the current chunk MetaWord* allocate(size_t word_size);
*** 1317,1350 **** } return false; } ! Metachunk* VirtualSpaceList::get_new_chunk(size_t word_size, ! size_t grow_chunks_by_words, ! size_t medium_chunk_bunch) { // Allocate a chunk out of the current virtual space. ! Metachunk* next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); if (next != NULL) { return next; } // The expand amount is currently only determined by the requested sizes // and not how much committed memory is left in the current virtual space. ! size_t min_word_size = align_size_up(grow_chunks_by_words, Metaspace::commit_alignment_words()); ! size_t preferred_word_size = align_size_up(medium_chunk_bunch, Metaspace::commit_alignment_words()); if (min_word_size >= preferred_word_size) { // Can happen when humongous chunks are allocated. preferred_word_size = min_word_size; } bool expanded = expand_by(min_word_size, preferred_word_size); if (expanded) { ! next = current_virtual_space()->get_chunk_vs(grow_chunks_by_words); assert(next != NULL, "The allocation was expected to succeed after the expansion"); } return next; } --- 1326,1357 ---- } return false; } ! Metachunk* VirtualSpaceList::get_new_chunk(size_t chunk_word_size, size_t suggested_commit_granularity) { // Allocate a chunk out of the current virtual space. ! Metachunk* next = current_virtual_space()->get_chunk_vs(chunk_word_size); if (next != NULL) { return next; } // The expand amount is currently only determined by the requested sizes // and not how much committed memory is left in the current virtual space. ! size_t min_word_size = align_size_up(chunk_word_size, Metaspace::commit_alignment_words()); ! size_t preferred_word_size = align_size_up(suggested_commit_granularity, Metaspace::commit_alignment_words()); if (min_word_size >= preferred_word_size) { // Can happen when humongous chunks are allocated. preferred_word_size = min_word_size; } bool expanded = expand_by(min_word_size, preferred_word_size); if (expanded) { ! next = current_virtual_space()->get_chunk_vs(chunk_word_size); assert(next != NULL, "The allocation was expected to succeed after the expansion"); } return next; }
*** 1881,1920 **** } } // SpaceManager methods ! void SpaceManager::get_initial_chunk_sizes(Metaspace::MetaspaceType type, ! size_t* chunk_word_size, ! size_t* class_chunk_word_size) { switch (type) { ! case Metaspace::BootMetaspaceType: ! *chunk_word_size = Metaspace::first_chunk_word_size(); ! *class_chunk_word_size = Metaspace::first_class_chunk_word_size(); ! break; ! case Metaspace::ROMetaspaceType: ! *chunk_word_size = SharedReadOnlySize / wordSize; ! *class_chunk_word_size = ClassSpecializedChunk; ! break; ! case Metaspace::ReadWriteMetaspaceType: ! *chunk_word_size = SharedReadWriteSize / wordSize; ! *class_chunk_word_size = ClassSpecializedChunk; ! break; ! case Metaspace::AnonymousMetaspaceType: ! case Metaspace::ReflectionMetaspaceType: ! *chunk_word_size = SpecializedChunk; ! *class_chunk_word_size = ClassSpecializedChunk; ! break; ! default: ! *chunk_word_size = SmallChunk; ! *class_chunk_word_size = ClassSmallChunk; ! break; ! } ! assert(*chunk_word_size != 0 && *class_chunk_word_size != 0, ! err_msg("Initial chunks sizes bad: data " SIZE_FORMAT ! " class " SIZE_FORMAT, ! *chunk_word_size, *class_chunk_word_size)); } size_t SpaceManager::sum_free_in_chunks_in_use() const { MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); size_t free = 0; --- 1888,1949 ---- } } // SpaceManager methods ! size_t SpaceManager::adjust_initial_chunk_size(size_t requested, bool is_class_space) { ! size_t chunk_sizes[] = { ! specialized_chunk_size(is_class_space), ! small_chunk_size(is_class_space), ! medium_chunk_size(is_class_space) ! }; ! ! // Adjust up to one of the fixed chunk sizes ... ! for (size_t i = 0; i < ARRAY_SIZE(chunk_sizes); i++) { ! if (requested <= chunk_sizes[i]) { ! return chunk_sizes[i]; ! } ! } ! ! // ... or return the size as a humongous chunk. ! return requested; ! } ! ! size_t SpaceManager::adjust_initial_chunk_size(size_t requested) const { ! return adjust_initial_chunk_size(requested, is_class()); ! } ! ! size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const { ! size_t requested; ! ! if (is_class()) { switch (type) { ! case Metaspace::BootMetaspaceType: requested = Metaspace::first_class_chunk_word_size(); break; ! case Metaspace::ROMetaspaceType: requested = ClassSpecializedChunk; break; ! case Metaspace::ReadWriteMetaspaceType: requested = ClassSpecializedChunk; break; ! case Metaspace::AnonymousMetaspaceType: requested = ClassSpecializedChunk; break; ! case Metaspace::ReflectionMetaspaceType: requested = ClassSpecializedChunk; break; ! default: requested = ClassSmallChunk; break; ! } ! } else { ! switch (type) { ! case Metaspace::BootMetaspaceType: requested = Metaspace::first_chunk_word_size(); break; ! case Metaspace::ROMetaspaceType: requested = SharedReadOnlySize / wordSize; break; ! case Metaspace::ReadWriteMetaspaceType: requested = SharedReadWriteSize / wordSize; break; ! case Metaspace::AnonymousMetaspaceType: requested = SpecializedChunk; break; ! case Metaspace::ReflectionMetaspaceType: requested = SpecializedChunk; break; ! default: requested = SmallChunk; break; ! } ! } ! ! // Adjust to one of the fixed chunk sizes (unless humongous) ! const size_t adjusted = adjust_initial_chunk_size(requested); ! ! assert(adjusted != 0, err_msg("Incorrect initial chunk size. Requested: " ! SIZE_FORMAT " adjusted: " SIZE_FORMAT, requested, adjusted)); ! ! return adjusted; } size_t SpaceManager::sum_free_in_chunks_in_use() const { MutexLockerEx cl(lock(), Mutex::_no_safepoint_check_flag); size_t free = 0;
*** 2100,2111 **** " words left", word_size, words_used, words_left); } // Get another chunk out of the virtual space ! size_t grow_chunks_by_words = calc_chunk_size(word_size); ! Metachunk* next = get_new_chunk(word_size, grow_chunks_by_words); MetaWord* mem = NULL; // If a chunk was available, add it to the in-use chunk list // and do an allocation from it. --- 2129,2140 ---- " words left", word_size, words_used, words_left); } // Get another chunk out of the virtual space ! size_t chunk_word_size = calc_chunk_size(word_size); ! Metachunk* next = get_new_chunk(chunk_word_size); MetaWord* mem = NULL; // If a chunk was available, add it to the in-use chunk list // and do an allocation from it.
*** 2410,2427 **** inc_used_metrics(remaining_words); } } } ! Metachunk* SpaceManager::get_new_chunk(size_t word_size, ! size_t grow_chunks_by_words) { // Get a chunk from the chunk freelist ! Metachunk* next = chunk_manager()->chunk_freelist_allocate(grow_chunks_by_words); if (next == NULL) { ! next = vs_list()->get_new_chunk(word_size, ! grow_chunks_by_words, medium_chunk_bunch()); } if (TraceMetadataHumongousAllocation && next != NULL && SpaceManager::is_humongous(next->word_size())) { --- 2439,2454 ---- inc_used_metrics(remaining_words); } } } ! Metachunk* SpaceManager::get_new_chunk(size_t chunk_word_size) { // Get a chunk from the chunk freelist ! Metachunk* next = chunk_manager()->chunk_freelist_allocate(chunk_word_size); if (next == NULL) { ! next = vs_list()->get_new_chunk(chunk_word_size, medium_chunk_bunch()); } if (TraceMetadataHumongousAllocation && next != NULL && SpaceManager::is_humongous(next->word_size())) {
*** 3083,3093 **** // The reserved space size may be bigger because of alignment, esp with UseLargePages assert(rs.size() >= CompressedClassSpaceSize, err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize)); assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); ! _chunk_manager_class = new ChunkManager(SpecializedChunk, ClassSmallChunk, ClassMediumChunk); if (!_class_space_list->initialization_succeeded()) { vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); } } --- 3110,3120 ---- // The reserved space size may be bigger because of alignment, esp with UseLargePages assert(rs.size() >= CompressedClassSpaceSize, err_msg(SIZE_FORMAT " != " UINTX_FORMAT, rs.size(), CompressedClassSpaceSize)); assert(using_class_space(), "Must be using class space"); _class_space_list = new VirtualSpaceList(rs); ! _chunk_manager_class = new ChunkManager(ClassSpecializedChunk, ClassSmallChunk, ClassMediumChunk); if (!_class_space_list->initialization_succeeded()) { vm_exit_during_initialization("Failed to setup compressed class space virtual space list."); } }
*** 3284,3353 **** void Metaspace::post_initialize() { MetaspaceGC::post_initialize(); } ! Metachunk* Metaspace::get_initialization_chunk(MetadataType mdtype, ! size_t chunk_word_size, ! size_t chunk_bunch) { // Get a chunk from the chunk freelist Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size); ! if (chunk != NULL) { ! return chunk; } ! return get_space_list(mdtype)->get_new_chunk(chunk_word_size, chunk_word_size, chunk_bunch); } ! void Metaspace::initialize(Mutex* lock, MetaspaceType type) { ! assert(space_list() != NULL, ! "Metadata VirtualSpaceList has not been initialized"); ! assert(chunk_manager_metadata() != NULL, ! "Metadata ChunkManager has not been initialized"); _vsm = new SpaceManager(NonClassType, lock); - if (_vsm == NULL) { - return; - } - size_t word_size; - size_t class_word_size; - vsm()->get_initial_chunk_sizes(type, &word_size, &class_word_size); if (using_class_space()) { - assert(class_space_list() != NULL, - "Class VirtualSpaceList has not been initialized"); - assert(chunk_manager_class() != NULL, - "Class ChunkManager has not been initialized"); - // Allocate SpaceManager for classes. _class_vsm = new SpaceManager(ClassType, lock); - if (_class_vsm == NULL) { - return; - } } MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); // Allocate chunk for metadata objects ! Metachunk* new_chunk = get_initialization_chunk(NonClassType, ! word_size, ! vsm()->medium_chunk_bunch()); ! assert(!DumpSharedSpaces || new_chunk != NULL, "should have enough space for both chunks"); ! if (new_chunk != NULL) { ! // Add to this manager's list of chunks in use and current_chunk(). ! vsm()->add_chunk(new_chunk, true); ! } // Allocate chunk for class metadata objects if (using_class_space()) { ! Metachunk* class_chunk = get_initialization_chunk(ClassType, ! class_word_size, ! class_vsm()->medium_chunk_bunch()); ! if (class_chunk != NULL) { ! class_vsm()->add_chunk(class_chunk, true); ! } } _alloc_record_head = NULL; _alloc_record_tail = NULL; } --- 3311,3376 ---- void Metaspace::post_initialize() { MetaspaceGC::post_initialize(); } ! void Metaspace::initialize_first_chunk(MetaspaceType type, MetadataType mdtype) { ! Metachunk* chunk = get_initialization_chunk(type, mdtype); ! if (chunk != NULL) { ! // Add to this manager's list of chunks in use and current_chunk(). ! get_space_manager(mdtype)->add_chunk(chunk, true); ! } ! } ! ! Metachunk* Metaspace::get_initialization_chunk(MetaspaceType type, MetadataType mdtype) { ! size_t chunk_word_size = get_space_manager(mdtype)->get_initial_chunk_size(type); ! // Get a chunk from the chunk freelist Metachunk* chunk = get_chunk_manager(mdtype)->chunk_freelist_allocate(chunk_word_size); ! ! if (chunk == NULL) { ! chunk = get_space_list(mdtype)->get_new_chunk(chunk_word_size, ! get_space_manager(mdtype)->medium_chunk_bunch()); ! } ! ! // For dumping shared archive, report error if allocation has failed. ! if (DumpSharedSpaces && chunk == NULL) { ! report_insufficient_metaspace(MetaspaceAux::committed_bytes() + chunk_word_size * BytesPerWord); } ! return chunk; } ! void Metaspace::verify_global_initialization() { ! assert(space_list() != NULL, "Metadata VirtualSpaceList has not been initialized"); ! assert(chunk_manager_metadata() != NULL, "Metadata ChunkManager has not been initialized"); ! if (using_class_space()) { ! assert(class_space_list() != NULL, "Class VirtualSpaceList has not been initialized"); ! assert(chunk_manager_class() != NULL, "Class ChunkManager has not been initialized"); ! } ! } + void Metaspace::initialize(Mutex* lock, MetaspaceType type) { + verify_global_initialization(); + + // Allocate SpaceManager for metadata objects. _vsm = new SpaceManager(NonClassType, lock); if (using_class_space()) { // Allocate SpaceManager for classes. _class_vsm = new SpaceManager(ClassType, lock); } MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); // Allocate chunk for metadata objects ! initialize_first_chunk(type, NonClassType); // Allocate chunk for class metadata objects if (using_class_space()) { ! initialize_first_chunk(type, ClassType); } _alloc_record_head = NULL; _alloc_record_tail = NULL; }
*** 3770,3780 **** MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); // A size larger than VirtualSpaceSize (256k) and add one page to make it _not_ be // vm_allocation_granularity aligned on Windows. size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord)); large_size += (os::vm_page_size()/BytesPerWord); ! vs_list->get_new_chunk(large_size, large_size, 0); } static void test() { test_reserved(); test_committed(); --- 3793,3803 ---- MutexLockerEx cl(SpaceManager::expand_lock(), Mutex::_no_safepoint_check_flag); // A size larger than VirtualSpaceSize (256k) and add one page to make it _not_ be // vm_allocation_granularity aligned on Windows. size_t large_size = (size_t)(2*256*K + (os::vm_page_size()/BytesPerWord)); large_size += (os::vm_page_size()/BytesPerWord); ! vs_list->get_new_chunk(large_size, 0); } static void test() { test_reserved(); test_committed();
*** 3945,3950 **** --- 3968,4023 ---- void TestVirtualSpaceNode_test() { TestVirtualSpaceNodeTest::test(); TestVirtualSpaceNodeTest::test_is_available(); } + + // The following test is placed here instead of a gtest / unittest file + // because the ChunkManager class is only available in this file. + class SpaceManagerTest : AllStatic { + friend void SpaceManager_test_adjust_initial_chunk_size(); + + static void test_adjust_initial_chunk_size(bool is_class) { + const size_t smallest = SpaceManager::smallest_chunk_size(is_class); + const size_t normal = SpaceManager::small_chunk_size(is_class); + const size_t medium = SpaceManager::medium_chunk_size(is_class); + + #define test_adjust_initial_chunk_size(value, expected, is_class_value) \ + do { \ + size_t v = value; \ + size_t e = expected; \ + assert(SpaceManager::adjust_initial_chunk_size(v, (is_class_value)) == e, \ + err_msg("Expected: " SIZE_FORMAT " got: " SIZE_FORMAT, e, v)); \ + } while (0) + + // Smallest (specialized) + test_adjust_initial_chunk_size(1, smallest, is_class); + test_adjust_initial_chunk_size(smallest - 1, smallest, is_class); + test_adjust_initial_chunk_size(smallest, smallest, is_class); + + // Small + test_adjust_initial_chunk_size(smallest + 1, normal, is_class); + test_adjust_initial_chunk_size(normal - 1, normal, is_class); + test_adjust_initial_chunk_size(normal, normal, is_class); + + // Medium + test_adjust_initial_chunk_size(normal + 1, medium, is_class); + test_adjust_initial_chunk_size(medium - 1, medium, is_class); + test_adjust_initial_chunk_size(medium, medium, is_class); + + // Humongous + test_adjust_initial_chunk_size(medium + 1, medium + 1, is_class); + + #undef test_adjust_initial_chunk_size + } + + static void test_adjust_initial_chunk_size() { + test_adjust_initial_chunk_size(false); + test_adjust_initial_chunk_size(true); + } + }; + + void SpaceManager_test_adjust_initial_chunk_size() { + SpaceManagerTest::test_adjust_initial_chunk_size(); + } + #endif
< prev index next >