214 "(now: " SIZE_FORMAT ", decrement value: " SIZE_FORMAT ").", _free_chunks_total, c->word_size()); |
213 "(now: " SIZE_FORMAT ", decrement value: " SIZE_FORMAT ").", _free_chunks_total, c->word_size()); |
215 _free_chunks_count --; |
214 _free_chunks_count --; |
216 _free_chunks_total -= c->word_size(); |
215 _free_chunks_total -= c->word_size(); |
217 } |
216 } |
218 |
217 |
219 size_t ChunkManager::free_chunks_count() { |
|
220 #ifdef ASSERT |
|
221 if (!UseConcMarkSweepGC && !MetaspaceExpand_lock->is_locked()) { |
|
222 MutexLockerEx cl(MetaspaceExpand_lock, |
|
223 Mutex::_no_safepoint_check_flag); |
|
224 // This lock is only needed in debug because the verification |
|
225 // of the _free_chunks_totals walks the list of free chunks |
|
226 slow_locked_verify_free_chunks_count(); |
|
227 } |
|
228 #endif |
|
229 return _free_chunks_count; |
|
230 } |
|
231 |
|
232 ChunkIndex ChunkManager::list_index(size_t size) { |
218 ChunkIndex ChunkManager::list_index(size_t size) { |
233 return get_chunk_type_by_size(size, is_class()); |
219 return get_chunk_type_by_size(size, is_class()); |
234 } |
220 } |
235 |
221 |
236 size_t ChunkManager::size_by_index(ChunkIndex index) const { |
222 size_t ChunkManager::size_by_index(ChunkIndex index) const { |
237 index_bounds_check(index); |
223 index_bounds_check(index); |
238 assert(index != HumongousIndex, "Do not call for humongous chunks."); |
224 assert(index != HumongousIndex, "Do not call for humongous chunks."); |
239 return get_size_for_nonhumongous_chunktype(index, is_class()); |
225 return get_size_for_nonhumongous_chunktype(index, is_class()); |
240 } |
226 } |
241 |
227 |
242 void ChunkManager::locked_verify_free_chunks_total() { |
228 #ifdef ASSERT |
243 assert_lock_strong(MetaspaceExpand_lock); |
229 void ChunkManager::verify(bool slow) const { |
244 assert(sum_free_chunks() == _free_chunks_total, |
|
245 "_free_chunks_total " SIZE_FORMAT " is not the" |
|
246 " same as sum " SIZE_FORMAT, _free_chunks_total, |
|
247 sum_free_chunks()); |
|
248 } |
|
249 |
|
250 void ChunkManager::locked_verify_free_chunks_count() { |
|
251 assert_lock_strong(MetaspaceExpand_lock); |
|
252 assert(sum_free_chunks_count() == _free_chunks_count, |
|
253 "_free_chunks_count " SIZE_FORMAT " is not the" |
|
254 " same as sum " SIZE_FORMAT, _free_chunks_count, |
|
255 sum_free_chunks_count()); |
|
256 } |
|
257 |
|
258 void ChunkManager::verify() { |
|
259 MutexLockerEx cl(MetaspaceExpand_lock, |
230 MutexLockerEx cl(MetaspaceExpand_lock, |
260 Mutex::_no_safepoint_check_flag); |
231 Mutex::_no_safepoint_check_flag); |
261 locked_verify(); |
232 locked_verify(slow); |
262 } |
233 } |
263 |
234 |
264 void ChunkManager::locked_verify() { |
235 void ChunkManager::locked_verify(bool slow) const { |
265 locked_verify_free_chunks_count(); |
236 log_trace(gc, metaspace, freelist)("verifying %s chunkmanager (%s).", |
266 locked_verify_free_chunks_total(); |
237 (is_class() ? "class space" : "metaspace"), (slow ? "slow" : "quick")); |
|
238 |
|
239 assert_lock_strong(MetaspaceExpand_lock); |
|
240 |
|
241 size_t chunks_counted = 0; |
|
242 size_t wordsize_chunks_counted = 0; |
267 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { |
243 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { |
268 ChunkList* list = free_chunks(i); |
244 const ChunkList* list = _free_chunks + i; |
269 if (list != NULL) { |
245 if (list != NULL) { |
270 Metachunk* chunk = list->head(); |
246 Metachunk* chunk = list->head(); |
271 while (chunk) { |
247 while (chunk) { |
272 DEBUG_ONLY(do_verify_chunk(chunk);) |
248 if (slow) { |
|
249 do_verify_chunk(chunk); |
|
250 } |
273 assert(chunk->is_tagged_free(), "Chunk should be tagged as free."); |
251 assert(chunk->is_tagged_free(), "Chunk should be tagged as free."); |
|
252 chunks_counted ++; |
|
253 wordsize_chunks_counted += chunk->size(); |
274 chunk = chunk->next(); |
254 chunk = chunk->next(); |
275 } |
255 } |
276 } |
256 } |
277 } |
257 } |
278 } |
258 |
|
259 chunks_counted += humongous_dictionary()->total_free_blocks(); |
|
260 wordsize_chunks_counted += humongous_dictionary()->total_size(); |
|
261 |
|
262 assert(chunks_counted == _free_chunks_count && wordsize_chunks_counted == _free_chunks_total, |
|
263 "freelist accounting mismatch: " |
|
264 "we think: " SIZE_FORMAT " chunks, total " SIZE_FORMAT " words, " |
|
265 "reality: " SIZE_FORMAT " chunks, total " SIZE_FORMAT " words.", |
|
266 _free_chunks_count, _free_chunks_total, |
|
267 chunks_counted, wordsize_chunks_counted); |
|
268 } |
|
269 #endif // ASSERT |
279 |
270 |
280 void ChunkManager::locked_print_free_chunks(outputStream* st) { |
271 void ChunkManager::locked_print_free_chunks(outputStream* st) { |
281 assert_lock_strong(MetaspaceExpand_lock); |
272 assert_lock_strong(MetaspaceExpand_lock); |
282 st->print_cr("Free chunk total " SIZE_FORMAT " count " SIZE_FORMAT, |
273 st->print_cr("Free chunk total " SIZE_FORMAT " count " SIZE_FORMAT, |
283 _free_chunks_total, _free_chunks_count); |
274 _free_chunks_total, _free_chunks_count); |
284 } |
|
285 |
|
286 void ChunkManager::locked_print_sum_free_chunks(outputStream* st) { |
|
287 assert_lock_strong(MetaspaceExpand_lock); |
|
288 st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT, |
|
289 sum_free_chunks(), sum_free_chunks_count()); |
|
290 } |
275 } |
291 |
276 |
292 ChunkList* ChunkManager::free_chunks(ChunkIndex index) { |
277 ChunkList* ChunkManager::free_chunks(ChunkIndex index) { |
293 assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex, |
278 assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex, |
294 "Bad index: %d", (int)index); |
279 "Bad index: %d", (int)index); |
295 |
|
296 return &_free_chunks[index]; |
280 return &_free_chunks[index]; |
297 } |
|
298 |
|
299 // These methods that sum the free chunk lists are used in printing |
|
300 // methods that are used in product builds. |
|
301 size_t ChunkManager::sum_free_chunks() { |
|
302 assert_lock_strong(MetaspaceExpand_lock); |
|
303 size_t result = 0; |
|
304 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { |
|
305 ChunkList* list = free_chunks(i); |
|
306 |
|
307 if (list == NULL) { |
|
308 continue; |
|
309 } |
|
310 |
|
311 result = result + list->count() * list->size(); |
|
312 } |
|
313 result = result + humongous_dictionary()->total_size(); |
|
314 return result; |
|
315 } |
|
316 |
|
317 size_t ChunkManager::sum_free_chunks_count() { |
|
318 assert_lock_strong(MetaspaceExpand_lock); |
|
319 size_t count = 0; |
|
320 for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) { |
|
321 ChunkList* list = free_chunks(i); |
|
322 if (list == NULL) { |
|
323 continue; |
|
324 } |
|
325 count = count + list->count(); |
|
326 } |
|
327 count = count + humongous_dictionary()->total_free_blocks(); |
|
328 return count; |
|
329 } |
281 } |
330 |
282 |
331 ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) { |
283 ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) { |
332 ChunkIndex index = list_index(word_size); |
284 ChunkIndex index = list_index(word_size); |
333 assert(index < HumongousIndex, "No humongous list"); |
285 assert(index < HumongousIndex, "No humongous list"); |
568 |
528 |
569 return chunk; |
529 return chunk; |
570 } |
530 } |
571 |
531 |
572 void ChunkManager::return_single_chunk(Metachunk* chunk) { |
532 void ChunkManager::return_single_chunk(Metachunk* chunk) { |
|
533 |
|
534 #ifdef ASSERT |
|
535 EVERY_NTH(VerifyMetaspaceInterval) |
|
536 this->locked_verify(false); |
|
537 do_verify_chunk(chunk); |
|
538 END_EVERY_NTH |
|
539 #endif |
|
540 |
573 const ChunkIndex index = chunk->get_chunk_type(); |
541 const ChunkIndex index = chunk->get_chunk_type(); |
574 assert_lock_strong(MetaspaceExpand_lock); |
542 assert_lock_strong(MetaspaceExpand_lock); |
575 DEBUG_ONLY(do_verify_chunk(chunk);) |
543 DEBUG_ONLY(g_internal_statistics.num_chunks_added_to_freelist ++;) |
576 assert(chunk != NULL, "Expected chunk."); |
544 assert(chunk != NULL, "Expected chunk."); |
577 assert(chunk->container() != NULL, "Container should have been set."); |
545 assert(chunk->container() != NULL, "Container should have been set."); |
578 assert(chunk->is_tagged_free() == false, "Chunk should be in use."); |
546 assert(chunk->is_tagged_free() == false, "Chunk should be in use."); |
579 index_bounds_check(index); |
547 index_bounds_check(index); |
580 |
548 |
581 // Note: mangle *before* returning the chunk to the freelist or dictionary. It does not |
549 // Note: mangle *before* returning the chunk to the freelist or dictionary. It does not |
582 // matter for the freelist (non-humongous chunks), but the humongous chunk dictionary |
550 // matter for the freelist (non-humongous chunks), but the humongous chunk dictionary |
583 // keeps tree node pointers in the chunk payload area which mangle will overwrite. |
551 // keeps tree node pointers in the chunk payload area which mangle will overwrite. |
584 DEBUG_ONLY(chunk->mangle(badMetaWordVal);) |
552 DEBUG_ONLY(chunk->mangle(badMetaWordVal);) |
|
553 |
|
554 // may need node for verification later after chunk may have been merged away. |
|
555 DEBUG_ONLY(VirtualSpaceNode* vsn = chunk->container(); ) |
585 |
556 |
586 if (index != HumongousIndex) { |
557 if (index != HumongousIndex) { |
587 // Return non-humongous chunk to freelist. |
558 // Return non-humongous chunk to freelist. |
588 ChunkList* list = free_chunks(index); |
559 ChunkList* list = free_chunks(index); |
589 assert(list->size() == chunk->word_size(), "Wrong chunk type."); |
560 assert(list->size() == chunk->word_size(), "Wrong chunk type."); |