# HG changeset patch # User jmasa # Date 1364838630 25200 # Node ID df254344edf1b15bf3afb0c9a39b1cce29985af0 # Parent 9aa8d8037ee3933790fd2f1cfb03721d8b61d2c4 8011173: NPG: Replace the ChunkList implementation with class FreeList Reviewed-by: mgerdin, tschatzl, johnc, coleenp diff -r 9aa8d8037ee3 -r df254344edf1 src/share/vm/memory/metaspace.cpp --- a/src/share/vm/memory/metaspace.cpp Tue Apr 16 12:46:24 2013 +0200 +++ b/src/share/vm/memory/metaspace.cpp Mon Apr 01 10:50:30 2013 -0700 @@ -103,27 +103,7 @@ // a chunk is placed on the free list of blocks (BlockFreelist) and // reused from there. -// Pointer to list of Metachunks. -class ChunkList VALUE_OBJ_CLASS_SPEC { - // List of free chunks - Metachunk* _head; - - public: - // Constructor - ChunkList() : _head(NULL) {} - - // Accessors - Metachunk* head() { return _head; } - void set_head(Metachunk* v) { _head = v; } - - // Link at head of the list - void add_at_head(Metachunk* head, Metachunk* tail); - void add_at_head(Metachunk* head); - - size_t sum_list_size(); - size_t sum_list_count(); - size_t sum_list_capacity(); -}; +typedef class FreeList ChunkList; // Manages the global free lists of chunks. // Has three lists of free chunks, and a total size and @@ -185,6 +165,10 @@ // for special, small, medium, and humongous chunks. static ChunkIndex list_index(size_t size); + // Add the simple linked list of chunks to the freelist of chunks + // of type index. + void return_chunks(ChunkIndex index, Metachunk* chunks); + // Total of the space in the free chunks list size_t free_chunks_total(); size_t free_chunks_total_in_bytes(); @@ -899,6 +883,9 @@ Mutex::_no_safepoint_check_flag); bool initialization_succeeded = grow_vs(word_size); + _chunk_manager.free_chunks(SpecializedIndex)->set_size(SpecializedChunk); + _chunk_manager.free_chunks(SmallIndex)->set_size(SmallChunk); + _chunk_manager.free_chunks(MediumIndex)->set_size(MediumChunk); assert(initialization_succeeded, " VirtualSpaceList initialization should not fail"); } @@ -913,6 +900,9 @@ Mutex::_no_safepoint_check_flag); VirtualSpaceNode* class_entry = new VirtualSpaceNode(rs); bool succeeded = class_entry->initialize(); + _chunk_manager.free_chunks(SpecializedIndex)->set_size(SpecializedChunk); + _chunk_manager.free_chunks(SmallIndex)->set_size(ClassSmallChunk); + _chunk_manager.free_chunks(MediumIndex)->set_size(ClassMediumChunk); assert(succeeded, " VirtualSpaceList initialization should not fail"); link_vs(class_entry, rs.size()/BytesPerWord); } @@ -1380,76 +1370,6 @@ } #endif -// ChunkList methods - -size_t ChunkList::sum_list_size() { - size_t result = 0; - Metachunk* cur = head(); - while (cur != NULL) { - result += cur->word_size(); - cur = cur->next(); - } - return result; -} - -size_t ChunkList::sum_list_count() { - size_t result = 0; - Metachunk* cur = head(); - while (cur != NULL) { - result++; - cur = cur->next(); - } - return result; -} - -size_t ChunkList::sum_list_capacity() { - size_t result = 0; - Metachunk* cur = head(); - while (cur != NULL) { - result += cur->capacity_word_size(); - cur = cur->next(); - } - return result; -} - -void ChunkList::add_at_head(Metachunk* head, Metachunk* tail) { - assert_lock_strong(SpaceManager::expand_lock()); - assert(head == tail || tail->next() == NULL, - "Not the tail or the head has already been added to a list"); - - if (TraceMetadataChunkAllocation && Verbose) { - gclog_or_tty->print("ChunkList::add_at_head(head, tail): "); - Metachunk* cur = head; - while (cur != NULL) { - gclog_or_tty->print(PTR_FORMAT " (" SIZE_FORMAT ") ", cur, cur->word_size()); - cur = cur->next(); - } - gclog_or_tty->print_cr(""); - } - - if (tail != NULL) { - tail->set_next(_head); - } - set_head(head); -} - -void ChunkList::add_at_head(Metachunk* list) { - if (list == NULL) { - // Nothing to add - return; - } - assert_lock_strong(SpaceManager::expand_lock()); - Metachunk* head = list; - Metachunk* tail = list; - Metachunk* cur = head->next(); - // Search for the tail since it is not passed. - while (cur != NULL) { - tail = cur; - cur = cur->next(); - } - add_at_head(head, tail); -} - // ChunkManager methods // Verification of _free_chunks_total and _free_chunks_count does not @@ -1553,7 +1473,7 @@ continue; } - result = result + list->sum_list_capacity(); + result = result + list->count() * list->size(); } result = result + humongous_dictionary()->total_size(); return result; @@ -1567,7 +1487,7 @@ if (list == NULL) { continue; } - count = count + list->sum_list_count(); + count = count + list->count(); } count = count + humongous_dictionary()->total_free_blocks(); return count; @@ -1622,7 +1542,7 @@ } // Remove the chunk as the head of the list. - free_list->set_head(chunk->next()); + free_list->remove_chunk(chunk); // Chunk is being removed from the chunks free list. dec_free_chunks_total(chunk->capacity_word_size()); @@ -1679,7 +1599,7 @@ size_t list_count; if (list_index(word_size) < HumongousIndex) { ChunkList* list = find_free_chunks_list(word_size); - list_count = list->sum_list_count(); + list_count = list->count(); } else { list_count = humongous_dictionary()->total_count(); } @@ -1958,6 +1878,29 @@ } } +void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { + if (chunks == NULL) { + return; + } + ChunkList* list = free_chunks(index); + assert(list->size() == chunks->word_size(), "Mismatch in chunk sizes"); + assert_lock_strong(SpaceManager::expand_lock()); + Metachunk* cur = chunks; + + // This return chunks one at a time. If a new + // class List can be created that is a base class + // of FreeList then something like FreeList::prepend() + // can be used in place of this loop + while (cur != NULL) { + // Capture the next link before it is changed + // by the call to return_chunk_at_head(); + Metachunk* next = cur->next(); + cur->set_is_free(true); + list->return_chunk_at_head(cur); + cur = next; + } +} + SpaceManager::~SpaceManager() { // This call this->_lock which can't be done while holding expand_lock() const size_t in_use_before = sum_capacity_in_chunks_in_use(); @@ -1995,11 +1938,11 @@ chunk_size_name(i)); } Metachunk* chunks = chunks_in_use(i); - chunk_manager->free_chunks(i)->add_at_head(chunks); + chunk_manager->return_chunks(i, chunks); set_chunks_in_use(i, NULL); if (TraceMetadataChunkAllocation && Verbose) { gclog_or_tty->print_cr("updated freelist count %d %s", - chunk_manager->free_chunks(i)->sum_list_count(), + chunk_manager->free_chunks(i)->count(), chunk_size_name(i)); } assert(i != HumongousIndex, "Humongous chunks are handled explicitly later");