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,