Mercurial > hg > graal-jvmci-8
comparison src/share/vm/memory/metaspace.cpp @ 12231:24e87613ee58
8009561: NPG: Metaspace fragmentation when retiring a Metachunk
Summary: Use best-fit block-splitting freelist allocation from the block freelist.
Reviewed-by: jmasa, stefank
author | mgerdin |
---|---|
date | Wed, 11 Sep 2013 09:37:14 +0200 |
parents | 7944aba7ba41 |
children | d6c266999345 |
comparison
equal
deleted
inserted
replaced
12227:440edcf30231 | 12231:24e87613ee58 |
---|---|
49 const bool metaspace_slow_verify = false; | 49 const bool metaspace_slow_verify = false; |
50 | 50 |
51 // Parameters for stress mode testing | 51 // Parameters for stress mode testing |
52 const uint metadata_deallocate_a_lot_block = 10; | 52 const uint metadata_deallocate_a_lot_block = 10; |
53 const uint metadata_deallocate_a_lock_chunk = 3; | 53 const uint metadata_deallocate_a_lock_chunk = 3; |
54 size_t const allocation_from_dictionary_limit = 64 * K; | 54 size_t const allocation_from_dictionary_limit = 4 * K; |
55 | 55 |
56 MetaWord* last_allocated = 0; | 56 MetaWord* last_allocated = 0; |
57 | 57 |
58 size_t Metaspace::_class_metaspace_size; | 58 size_t Metaspace::_class_metaspace_size; |
59 | 59 |
225 // Used to manage the free list of Metablocks (a block corresponds | 225 // Used to manage the free list of Metablocks (a block corresponds |
226 // to the allocation of a quantum of metadata). | 226 // to the allocation of a quantum of metadata). |
227 class BlockFreelist VALUE_OBJ_CLASS_SPEC { | 227 class BlockFreelist VALUE_OBJ_CLASS_SPEC { |
228 BlockTreeDictionary* _dictionary; | 228 BlockTreeDictionary* _dictionary; |
229 static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size); | 229 static Metablock* initialize_free_chunk(MetaWord* p, size_t word_size); |
230 | |
231 // Only allocate and split from freelist if the size of the allocation | |
232 // is at least 1/4th the size of the available block. | |
233 const static int WasteMultiplier = 4; | |
230 | 234 |
231 // Accessors | 235 // Accessors |
232 BlockTreeDictionary* dictionary() const { return _dictionary; } | 236 BlockTreeDictionary* dictionary() const { return _dictionary; } |
233 | 237 |
234 public: | 238 public: |
621 | 625 |
622 Metachunk* find_current_chunk(size_t word_size); | 626 Metachunk* find_current_chunk(size_t word_size); |
623 | 627 |
624 // Add chunk to the list of chunks in use | 628 // Add chunk to the list of chunks in use |
625 void add_chunk(Metachunk* v, bool make_current); | 629 void add_chunk(Metachunk* v, bool make_current); |
630 void retire_current_chunk(); | |
626 | 631 |
627 Mutex* lock() const { return _lock; } | 632 Mutex* lock() const { return _lock; } |
628 | 633 |
629 const char* chunk_size_name(ChunkIndex index) const; | 634 const char* chunk_size_name(ChunkIndex index) const; |
630 | 635 |
805 // Dark matter. Too small for dictionary. | 810 // Dark matter. Too small for dictionary. |
806 return NULL; | 811 return NULL; |
807 } | 812 } |
808 | 813 |
809 Metablock* free_block = | 814 Metablock* free_block = |
810 dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::exactly); | 815 dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::atLeast); |
811 if (free_block == NULL) { | 816 if (free_block == NULL) { |
812 return NULL; | 817 return NULL; |
813 } | 818 } |
814 | 819 |
815 return (MetaWord*) free_block; | 820 const size_t block_size = free_block->size(); |
821 if (block_size > WasteMultiplier * word_size) { | |
822 return_block((MetaWord*)free_block, block_size); | |
823 return NULL; | |
824 } | |
825 | |
826 MetaWord* new_block = (MetaWord*)free_block; | |
827 assert(block_size >= word_size, "Incorrect size of block from freelist"); | |
828 const size_t unused = block_size - word_size; | |
829 if (unused >= TreeChunk<Metablock, FreeList>::min_size()) { | |
830 return_block(new_block + word_size, unused); | |
831 } | |
832 | |
833 return new_block; | |
816 } | 834 } |
817 | 835 |
818 void BlockFreelist::print_on(outputStream* st) const { | 836 void BlockFreelist::print_on(outputStream* st) const { |
819 if (dictionary() == NULL) { | 837 if (dictionary() == NULL) { |
820 return; | 838 return; |
2276 // Find the correct list and and set the current | 2294 // Find the correct list and and set the current |
2277 // chunk for that list. | 2295 // chunk for that list. |
2278 ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); | 2296 ChunkIndex index = ChunkManager::list_index(new_chunk->word_size()); |
2279 | 2297 |
2280 if (index != HumongousIndex) { | 2298 if (index != HumongousIndex) { |
2299 retire_current_chunk(); | |
2281 set_current_chunk(new_chunk); | 2300 set_current_chunk(new_chunk); |
2282 new_chunk->set_next(chunks_in_use(index)); | 2301 new_chunk->set_next(chunks_in_use(index)); |
2283 set_chunks_in_use(index, new_chunk); | 2302 set_chunks_in_use(index, new_chunk); |
2284 } else { | 2303 } else { |
2285 // For null class loader data and DumpSharedSpaces, the first chunk isn't | 2304 // For null class loader data and DumpSharedSpaces, the first chunk isn't |
2307 gclog_or_tty->print("SpaceManager::add_chunk: %d) ", | 2326 gclog_or_tty->print("SpaceManager::add_chunk: %d) ", |
2308 sum_count_in_chunks_in_use()); | 2327 sum_count_in_chunks_in_use()); |
2309 new_chunk->print_on(gclog_or_tty); | 2328 new_chunk->print_on(gclog_or_tty); |
2310 if (vs_list() != NULL) { | 2329 if (vs_list() != NULL) { |
2311 vs_list()->chunk_manager()->locked_print_free_chunks(tty); | 2330 vs_list()->chunk_manager()->locked_print_free_chunks(tty); |
2331 } | |
2332 } | |
2333 } | |
2334 | |
2335 void SpaceManager::retire_current_chunk() { | |
2336 if (current_chunk() != NULL) { | |
2337 size_t remaining_words = current_chunk()->free_word_size(); | |
2338 if (remaining_words >= TreeChunk<Metablock, FreeList>::min_size()) { | |
2339 block_freelists()->return_block(current_chunk()->allocate(remaining_words), remaining_words); | |
2340 inc_used_metrics(remaining_words); | |
2312 } | 2341 } |
2313 } | 2342 } |
2314 } | 2343 } |
2315 | 2344 |
2316 Metachunk* SpaceManager::get_new_chunk(size_t word_size, | 2345 Metachunk* SpaceManager::get_new_chunk(size_t word_size, |