794 } 795 796 void VirtualSpaceNode::dec_container_count() { 797 assert_lock_strong(SpaceManager::expand_lock()); 798 _container_count--; 799 } 800 801 #ifdef ASSERT 802 void VirtualSpaceNode::verify_container_count() { 803 assert(_container_count == container_count_slow(), 804 "Inconsistency in container_count _container_count " UINTX_FORMAT 805 " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow()); 806 } 807 #endif 808 809 // BlockFreelist methods 810 811 BlockFreelist::BlockFreelist() : _dictionary(new BlockTreeDictionary()) {} 812 813 BlockFreelist::~BlockFreelist() { 814 LogHandle(gc, metaspace, freelist) log; 815 if (log.is_trace()) { 816 ResourceMark rm; 817 dictionary()->print_free_lists(log.trace_stream()); 818 } 819 delete _dictionary; 820 } 821 822 void BlockFreelist::return_block(MetaWord* p, size_t word_size) { 823 Metablock* free_chunk = ::new (p) Metablock(word_size); 824 dictionary()->return_chunk(free_chunk); 825 } 826 827 MetaWord* BlockFreelist::get_block(size_t word_size) { 828 if (word_size < TreeChunk<Metablock, FreeList<Metablock> >::min_size()) { 829 // Dark matter. Too small for dictionary. 830 return NULL; 831 } 832 833 Metablock* free_block = 834 dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::atLeast); 835 if (free_block == NULL) { 836 return NULL; 837 } 838 2128 void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { 2129 if (chunks == NULL) { 2130 return; 2131 } 2132 ChunkList* list = free_chunks(index); 2133 assert(list->size() == chunks->word_size(), "Mismatch in chunk sizes"); 2134 assert_lock_strong(SpaceManager::expand_lock()); 2135 Metachunk* cur = chunks; 2136 2137 // This returns chunks one at a time. If a new 2138 // class List can be created that is a base class 2139 // of FreeList then something like FreeList::prepend() 2140 // can be used in place of this loop 2141 while (cur != NULL) { 2142 assert(cur->container() != NULL, "Container should have been set"); 2143 cur->container()->dec_container_count(); 2144 // Capture the next link before it is changed 2145 // by the call to return_chunk_at_head(); 2146 Metachunk* next = cur->next(); 2147 DEBUG_ONLY(cur->set_is_tagged_free(true);) 2148 list->return_chunk_at_head(cur); 2149 cur = next; 2150 } 2151 } 2152 2153 SpaceManager::~SpaceManager() { 2154 // This call this->_lock which can't be done while holding expand_lock() 2155 assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(), 2156 "sum_capacity_in_chunks_in_use() " SIZE_FORMAT 2157 " allocated_chunks_words() " SIZE_FORMAT, 2158 sum_capacity_in_chunks_in_use(), allocated_chunks_words()); 2159 2160 MutexLockerEx fcl(SpaceManager::expand_lock(), 2161 Mutex::_no_safepoint_check_flag); 2162 2163 chunk_manager()->slow_locked_verify(); 2164 2165 dec_total_from_size_metrics(); 2166 2167 LogHandle(gc, metaspace, freelist) log; 2168 if (log.is_trace()) { 2169 log.trace("~SpaceManager(): " PTR_FORMAT, p2i(this)); 2170 ResourceMark rm; 2171 locked_print_chunks_in_use_on(log.trace_stream()); 2172 } 2173 2174 // Do not mangle freed Metachunks. The chunk size inside Metachunks 2175 // is during the freeing of a VirtualSpaceNodes. 2176 2177 // Have to update before the chunks_in_use lists are emptied 2178 // below. 2179 chunk_manager()->inc_free_chunks_total(allocated_chunks_words(), 2180 sum_count_in_chunks_in_use()); 2181 2182 // Add all the chunks in use by this space manager 2183 // to the global list of free chunks. 2184 2185 // Follow each list of chunks-in-use and add them to the 2186 // free lists. Each list is NULL terminated. 2187 2188 for (ChunkIndex i = ZeroIndex; i < HumongousIndex; i = next_chunk_index(i)) { 2189 log.trace("returned " SIZE_FORMAT " %s chunks to freelist", sum_count_in_chunks_in_use(i), chunk_size_name(i)); 2190 Metachunk* chunks = chunks_in_use(i); 2191 chunk_manager()->return_chunks(i, chunks); 2192 set_chunks_in_use(i, NULL); 2193 log.trace("updated freelist count " SSIZE_FORMAT " %s", chunk_manager()->free_chunks(i)->count(), chunk_size_name(i)); 2194 assert(i != HumongousIndex, "Humongous chunks are handled explicitly later"); 2195 } 2196 2197 // The medium chunk case may be optimized by passing the head and 2198 // tail of the medium chunk list to add_at_head(). The tail is often 2199 // the current chunk but there are probably exceptions. 2200 2201 // Humongous chunks 2202 log.trace("returned " SIZE_FORMAT " %s humongous chunks to dictionary", 2203 sum_count_in_chunks_in_use(HumongousIndex), chunk_size_name(HumongousIndex)); 2204 log.trace("Humongous chunk dictionary: "); 2205 // Humongous chunks are never the current chunk. 2206 Metachunk* humongous_chunks = chunks_in_use(HumongousIndex); 2207 2208 while (humongous_chunks != NULL) { 2209 #ifdef ASSERT 2210 humongous_chunks->set_is_tagged_free(true); 2211 #endif 2212 log.trace(PTR_FORMAT " (" SIZE_FORMAT ") ", p2i(humongous_chunks), humongous_chunks->word_size()); 2213 assert(humongous_chunks->word_size() == (size_t) 2214 align_size_up(humongous_chunks->word_size(), 2215 smallest_chunk_size()), 2216 "Humongous chunk size is wrong: word size " SIZE_FORMAT 2217 " granularity " SIZE_FORMAT, 2218 humongous_chunks->word_size(), smallest_chunk_size()); 2219 Metachunk* next_humongous_chunks = humongous_chunks->next(); 2220 humongous_chunks->container()->dec_container_count(); 2221 chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); 2222 humongous_chunks = next_humongous_chunks; 2223 } 2224 log.trace("updated dictionary count " SIZE_FORMAT " %s", chunk_manager()->humongous_dictionary()->total_count(), chunk_size_name(HumongousIndex)); 2225 chunk_manager()->slow_locked_verify(); 2226 } 2227 2228 const char* SpaceManager::chunk_size_name(ChunkIndex index) const { 2229 switch (index) { 2230 case SpecializedIndex: 2231 return "Specialized"; | 794 } 795 796 void VirtualSpaceNode::dec_container_count() { 797 assert_lock_strong(SpaceManager::expand_lock()); 798 _container_count--; 799 } 800 801 #ifdef ASSERT 802 void VirtualSpaceNode::verify_container_count() { 803 assert(_container_count == container_count_slow(), 804 "Inconsistency in container_count _container_count " UINTX_FORMAT 805 " container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow()); 806 } 807 #endif 808 809 // BlockFreelist methods 810 811 BlockFreelist::BlockFreelist() : _dictionary(new BlockTreeDictionary()) {} 812 813 BlockFreelist::~BlockFreelist() { 814 delete _dictionary; 815 } 816 817 void BlockFreelist::return_block(MetaWord* p, size_t word_size) { 818 Metablock* free_chunk = ::new (p) Metablock(word_size); 819 dictionary()->return_chunk(free_chunk); 820 } 821 822 MetaWord* BlockFreelist::get_block(size_t word_size) { 823 if (word_size < TreeChunk<Metablock, FreeList<Metablock> >::min_size()) { 824 // Dark matter. Too small for dictionary. 825 return NULL; 826 } 827 828 Metablock* free_block = 829 dictionary()->get_chunk(word_size, FreeBlockDictionary<Metablock>::atLeast); 830 if (free_block == NULL) { 831 return NULL; 832 } 833 2123 void ChunkManager::return_chunks(ChunkIndex index, Metachunk* chunks) { 2124 if (chunks == NULL) { 2125 return; 2126 } 2127 ChunkList* list = free_chunks(index); 2128 assert(list->size() == chunks->word_size(), "Mismatch in chunk sizes"); 2129 assert_lock_strong(SpaceManager::expand_lock()); 2130 Metachunk* cur = chunks; 2131 2132 // This returns chunks one at a time. If a new 2133 // class List can be created that is a base class 2134 // of FreeList then something like FreeList::prepend() 2135 // can be used in place of this loop 2136 while (cur != NULL) { 2137 assert(cur->container() != NULL, "Container should have been set"); 2138 cur->container()->dec_container_count(); 2139 // Capture the next link before it is changed 2140 // by the call to return_chunk_at_head(); 2141 Metachunk* next = cur->next(); 2142 DEBUG_ONLY(cur->set_is_tagged_free(true);) 2143 NOT_PRODUCT(cur->mangle(badMetaWordVal);) 2144 list->return_chunk_at_head(cur); 2145 cur = next; 2146 } 2147 } 2148 2149 SpaceManager::~SpaceManager() { 2150 // This call this->_lock which can't be done while holding expand_lock() 2151 assert(sum_capacity_in_chunks_in_use() == allocated_chunks_words(), 2152 "sum_capacity_in_chunks_in_use() " SIZE_FORMAT 2153 " allocated_chunks_words() " SIZE_FORMAT, 2154 sum_capacity_in_chunks_in_use(), allocated_chunks_words()); 2155 2156 MutexLockerEx fcl(SpaceManager::expand_lock(), 2157 Mutex::_no_safepoint_check_flag); 2158 2159 chunk_manager()->slow_locked_verify(); 2160 2161 dec_total_from_size_metrics(); 2162 2163 LogHandle(gc, metaspace, freelist) log; 2164 if (log.is_trace()) { 2165 log.trace("~SpaceManager(): " PTR_FORMAT, p2i(this)); 2166 ResourceMark rm; 2167 locked_print_chunks_in_use_on(log.trace_stream()); 2168 block_freelists()->print_on(log.trace_stream()); 2169 } 2170 2171 // Have to update before the chunks_in_use lists are emptied 2172 // below. 2173 chunk_manager()->inc_free_chunks_total(allocated_chunks_words(), 2174 sum_count_in_chunks_in_use()); 2175 2176 // Add all the chunks in use by this space manager 2177 // to the global list of free chunks. 2178 2179 // Follow each list of chunks-in-use and add them to the 2180 // free lists. Each list is NULL terminated. 2181 2182 for (ChunkIndex i = ZeroIndex; i < HumongousIndex; i = next_chunk_index(i)) { 2183 log.trace("returned " SIZE_FORMAT " %s chunks to freelist", sum_count_in_chunks_in_use(i), chunk_size_name(i)); 2184 Metachunk* chunks = chunks_in_use(i); 2185 chunk_manager()->return_chunks(i, chunks); 2186 set_chunks_in_use(i, NULL); 2187 log.trace("updated freelist count " SSIZE_FORMAT " %s", chunk_manager()->free_chunks(i)->count(), chunk_size_name(i)); 2188 assert(i != HumongousIndex, "Humongous chunks are handled explicitly later"); 2189 } 2190 2191 // The medium chunk case may be optimized by passing the head and 2192 // tail of the medium chunk list to add_at_head(). The tail is often 2193 // the current chunk but there are probably exceptions. 2194 2195 // Humongous chunks 2196 log.trace("returned " SIZE_FORMAT " %s humongous chunks to dictionary", 2197 sum_count_in_chunks_in_use(HumongousIndex), chunk_size_name(HumongousIndex)); 2198 log.trace("Humongous chunk dictionary: "); 2199 // Humongous chunks are never the current chunk. 2200 Metachunk* humongous_chunks = chunks_in_use(HumongousIndex); 2201 2202 while (humongous_chunks != NULL) { 2203 DEBUG_ONLY(humongous_chunks->set_is_tagged_free(true);) 2204 NOT_PRODUCT(humongous_chunks->mangle(badMetaWordVal);) 2205 log.trace(PTR_FORMAT " (" SIZE_FORMAT ") ", p2i(humongous_chunks), humongous_chunks->word_size()); 2206 assert(humongous_chunks->word_size() == (size_t) 2207 align_size_up(humongous_chunks->word_size(), 2208 smallest_chunk_size()), 2209 "Humongous chunk size is wrong: word size " SIZE_FORMAT 2210 " granularity " SIZE_FORMAT, 2211 humongous_chunks->word_size(), smallest_chunk_size()); 2212 Metachunk* next_humongous_chunks = humongous_chunks->next(); 2213 humongous_chunks->container()->dec_container_count(); 2214 chunk_manager()->humongous_dictionary()->return_chunk(humongous_chunks); 2215 humongous_chunks = next_humongous_chunks; 2216 } 2217 log.trace("updated dictionary count " SIZE_FORMAT " %s", chunk_manager()->humongous_dictionary()->total_count(), chunk_size_name(HumongousIndex)); 2218 chunk_manager()->slow_locked_verify(); 2219 } 2220 2221 const char* SpaceManager::chunk_size_name(ChunkIndex index) const { 2222 switch (index) { 2223 case SpecializedIndex: 2224 return "Specialized"; |