Wed, 11 Sep 2013 09:37:14 +0200
8009561: NPG: Metaspace fragmentation when retiring a Metachunk
Summary: Use best-fit block-splitting freelist allocation from the block freelist.
Reviewed-by: jmasa, stefank
src/share/vm/memory/metaspace.cpp | file | annotate | diff | comparison | revisions |
1.1 --- a/src/share/vm/memory/metaspace.cpp Wed Sep 11 08:57:02 2013 +0200 1.2 +++ b/src/share/vm/memory/metaspace.cpp Wed Sep 11 09:37:14 2013 +0200 1.3 @@ -51,7 +51,7 @@ 1.4 // Parameters for stress mode testing 1.5 const uint metadata_deallocate_a_lot_block = 10; 1.6 const uint metadata_deallocate_a_lock_chunk = 3; 1.7 -size_t const allocation_from_dictionary_limit = 64 * K; 1.8 +size_t const allocation_from_dictionary_limit = 4 * K; 1.9 1.10 MetaWord* last_allocated = 0; 1.11 1.12 @@ -228,6 +228,10 @@ 1.13 BlockTreeDictionary* _dictionary; 1.14 static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size); 1.15 1.16 + // Only allocate and split from freelist if the size of the allocation 1.17 + // is at least 1/4th the size of the available block. 1.18 + const static int WasteMultiplier = 4; 1.19 + 1.20 // Accessors 1.21 BlockTreeDictionary* dictionary() const { return _dictionary; } 1.22 1.23 @@ -623,6 +627,7 @@ 1.24 1.25 // Add chunk to the list of chunks in use 1.26 void add_chunk(Metachunk* v, bool make_current); 1.27 + void retire_current_chunk(); 1.28 1.29 Mutex* lock() const { return _lock; } 1.30 1.31 @@ -807,12 +812,25 @@ 1.32 } 1.33 1.34 Metablock* free_block = 1.35 - dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::exactly); 1.36 + dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::atLeast); 1.37 if (free_block == NULL) { 1.38 return NULL; 1.39 } 1.40 1.41 - return (MetaWord*) free_block; 1.42 + const size_t block_size = free_block->size(); 1.43 + if (block_size > WasteMultiplier * word_size) { 1.44 + return_block((MetaWord*)free_block, block_size); 1.45 + return NULL; 1.46 + } 1.47 + 1.48 + MetaWord* new_block = (MetaWord*)free_block; 1.49 + assert(block_size >= word_size, "Incorrect size of block from freelist"); 1.50 + const size_t unused = block_size - word_size; 1.51 + if (unused >= TreeChunk<Metablock, FreeList>::min_size()) { 1.52 + return_block(new_block + word_size, unused); 1.53 + } 1.54 + 1.55 + return new_block; 1.56 } 1.57 1.58 void BlockFreelist::print_on(outputStream* st) const { 1.59 @@ -2278,6 +2296,7 @@ 1.60 ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); 1.61 1.62 if (index != HumongousIndex) { 1.63 + retire_current_chunk(); 1.64 set_current_chunk(new_chunk); 1.65 new_chunk->set_next(chunks_in_use(index)); 1.66 set_chunks_in_use(index, new_chunk); 1.67 @@ -2313,6 +2332,16 @@ 1.68 } 1.69 } 1.70 1.71 +void SpaceManager::retire_current_chunk() { 1.72 + if (current_chunk() != NULL) { 1.73 + size_t remaining_words = current_chunk()->free_word_size(); 1.74 + if (remaining_words >= TreeChunk<Metablock, FreeList>::min_size()) { 1.75 + block_freelists()->return_block(current_chunk()->allocate(remaining_words), remaining_words); 1.76 + inc_used_metrics(remaining_words); 1.77 + } 1.78 + } 1.79 +} 1.80 + 1.81 Metachunk* SpaceManager::get_new_chunk(size_t word_size, 1.82 size_t grow_chunks_by_words) { 1.83