# HG changeset patch # User mgerdin # Date 1378885034 -7200 # Node ID 24e87613ee58f77a028721f112310ef7315829a1 # Parent 440edcf30231861a868cd9690d769f0efa8b54c6 8009561: NPG: Metaspace fragmentation when retiring a Metachunk Summary: Use best-fit block-splitting freelist allocation from the block freelist. Reviewed-by: jmasa, stefank diff -r 440edcf30231 -r 24e87613ee58 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Wed Sep 11 08:57:02 2013 +0200 +++ b/src/share/vm/memory/metaspace.cpp Wed Sep 11 09:37:14 2013 +0200 @@ -51,7 +51,7 @@ // Parameters for stress mode testing const uint metadata_deallocate_a_lot_block = 10; const uint metadata_deallocate_a_lock_chunk = 3; -size_t const allocation_from_dictionary_limit = 64 * K; +size_t const allocation_from_dictionary_limit = 4 * K; MetaWord* last_allocated = 0; @@ -228,6 +228,10 @@ BlockTreeDictionary* _dictionary; static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size); + // Only allocate and split from freelist if the size of the allocation + // is at least 1/4th the size of the available block. + const static int WasteMultiplier = 4; + // Accessors BlockTreeDictionary* dictionary() const { return _dictionary; } @@ -623,6 +627,7 @@ // Add chunk to the list of chunks in use void add_chunk(Metachunk* v, bool make_current); + void retire_current_chunk(); Mutex* lock() const { return _lock; } @@ -807,12 +812,25 @@ } Metablock* free_block = - dictionary()->get_chunk(word_size, FreeBlockDictionary::exactly); + dictionary()->get_chunk(word_size, FreeBlockDictionary::atLeast); if (free_block == NULL) { return NULL; } - return (MetaWord*) free_block; + const size_t block_size = free_block->size(); + if (block_size > WasteMultiplier * word_size) { + return_block((MetaWord*)free_block, block_size); + return NULL; + } + + MetaWord* new_block = (MetaWord*)free_block; + assert(block_size >= word_size, "Incorrect size of block from freelist"); + const size_t unused = block_size - word_size; + if (unused >= TreeChunk::min_size()) { + return_block(new_block + word_size, unused); + } + + return new_block; } void BlockFreelist::print_on(outputStream* st) const { @@ -2278,6 +2296,7 @@ ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); if (index != HumongousIndex) { + retire_current_chunk(); set_current_chunk(new_chunk); new_chunk->set_next(chunks_in_use(index)); set_chunks_in_use(index, new_chunk); @@ -2313,6 +2332,16 @@ } } +void SpaceManager::retire_current_chunk() { + if (current_chunk() != NULL) { + size_t remaining_words = current_chunk()->free_word_size(); + if (remaining_words >= TreeChunk::min_size()) { + block_freelists()->return_block(current_chunk()->allocate(remaining_words), remaining_words); + inc_used_metrics(remaining_words); + } + } +} + Metachunk* SpaceManager::get_new_chunk(size_t word_size, size_t grow_chunks_by_words) {