mirror of
https://github.com/openjdk/jdk.git
synced 2025-09-19 10:34:38 +02:00
8218988: Improve metaspace verifications
Reviewed-by: zgu, coleenp
This commit is contained in:
parent
8bec32b02f
commit
fb7bbfac57
10 changed files with 206 additions and 207 deletions
|
@ -440,7 +440,6 @@ size_t MetaspaceUtils::free_chunks_total_words(Metaspace::MetadataType mdtype) {
|
||||||
if (chunk_manager == NULL) {
|
if (chunk_manager == NULL) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
chunk_manager->slow_verify();
|
|
||||||
return chunk_manager->free_chunks_total_words();
|
return chunk_manager->free_chunks_total_words();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -793,6 +792,13 @@ void MetaspaceUtils::print_report(outputStream* out, size_t scale, int flags) {
|
||||||
out->print_cr("Number of times virtual space nodes were expanded: " UINTX_FORMAT ".", g_internal_statistics.num_committed_space_expanded);
|
out->print_cr("Number of times virtual space nodes were expanded: " UINTX_FORMAT ".", g_internal_statistics.num_committed_space_expanded);
|
||||||
out->print_cr("Number of deallocations: " UINTX_FORMAT " (" UINTX_FORMAT " external).", g_internal_statistics.num_deallocs, g_internal_statistics.num_external_deallocs);
|
out->print_cr("Number of deallocations: " UINTX_FORMAT " (" UINTX_FORMAT " external).", g_internal_statistics.num_deallocs, g_internal_statistics.num_external_deallocs);
|
||||||
out->print_cr("Allocations from deallocated blocks: " UINTX_FORMAT ".", g_internal_statistics.num_allocs_from_deallocated_blocks);
|
out->print_cr("Allocations from deallocated blocks: " UINTX_FORMAT ".", g_internal_statistics.num_allocs_from_deallocated_blocks);
|
||||||
|
out->print_cr("Number of chunks added to freelist: " UINTX_FORMAT ".",
|
||||||
|
g_internal_statistics.num_chunks_added_to_freelist);
|
||||||
|
out->print_cr("Number of chunks removed from freelist: " UINTX_FORMAT ".",
|
||||||
|
g_internal_statistics.num_chunks_removed_from_freelist);
|
||||||
|
out->print_cr("Number of chunk merges: " UINTX_FORMAT ", split-ups: " UINTX_FORMAT ".",
|
||||||
|
g_internal_statistics.num_chunk_merges, g_internal_statistics.num_chunk_splits);
|
||||||
|
|
||||||
out->cr();
|
out->cr();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -844,10 +850,12 @@ void MetaspaceUtils::print_metaspace_map(outputStream* out, Metaspace::MetadataT
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaspaceUtils::verify_free_chunks() {
|
void MetaspaceUtils::verify_free_chunks() {
|
||||||
Metaspace::chunk_manager_metadata()->verify();
|
#ifdef ASSERT
|
||||||
|
Metaspace::chunk_manager_metadata()->verify(false);
|
||||||
if (Metaspace::using_class_space()) {
|
if (Metaspace::using_class_space()) {
|
||||||
Metaspace::chunk_manager_class()->verify();
|
Metaspace::chunk_manager_class()->verify(false);
|
||||||
}
|
}
|
||||||
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void MetaspaceUtils::verify_metrics() {
|
void MetaspaceUtils::verify_metrics() {
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "memory/freeList.inline.hpp"
|
#include "memory/freeList.inline.hpp"
|
||||||
#include "memory/metaspace/chunkManager.hpp"
|
#include "memory/metaspace/chunkManager.hpp"
|
||||||
#include "memory/metaspace/metachunk.hpp"
|
#include "memory/metaspace/metachunk.hpp"
|
||||||
|
#include "memory/metaspace/metaDebug.hpp"
|
||||||
#include "memory/metaspace/metaspaceCommon.hpp"
|
#include "memory/metaspace/metaspaceCommon.hpp"
|
||||||
#include "memory/metaspace/metaspaceStatistics.hpp"
|
#include "memory/metaspace/metaspaceStatistics.hpp"
|
||||||
#include "memory/metaspace/occupancyMap.hpp"
|
#include "memory/metaspace/occupancyMap.hpp"
|
||||||
|
@ -140,15 +141,21 @@ bool ChunkManager::attempt_to_coalesce_around_chunk(Metachunk* chunk, ChunkIndex
|
||||||
_free_chunks_count -= num_chunks_removed;
|
_free_chunks_count -= num_chunks_removed;
|
||||||
_free_chunks_count ++;
|
_free_chunks_count ++;
|
||||||
|
|
||||||
// VirtualSpaceNode::container_count does not have to be modified:
|
// VirtualSpaceNode::chunk_count does not have to be modified:
|
||||||
// it means "number of active (non-free) chunks", so merging free chunks
|
// it means "number of active (non-free) chunks", so merging free chunks
|
||||||
// should not affect that count.
|
// should not affect that count.
|
||||||
|
|
||||||
// At the end of a chunk merge, run verification tests.
|
// At the end of a chunk merge, run verification tests.
|
||||||
if (VerifyMetaspace) {
|
#ifdef ASSERT
|
||||||
DEBUG_ONLY(this->locked_verify());
|
|
||||||
DEBUG_ONLY(vsn->verify());
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
}
|
locked_verify(true);
|
||||||
|
vsn->verify(true);
|
||||||
|
END_EVERY_NTH
|
||||||
|
|
||||||
|
g_internal_statistics.num_chunk_merges ++;
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -189,14 +196,6 @@ int ChunkManager::remove_chunks_in_area(MetaWord* p, size_t word_size) {
|
||||||
return num_removed;
|
return num_removed;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ChunkManager::free_chunks_total_words() {
|
|
||||||
return _free_chunks_total;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ChunkManager::free_chunks_total_bytes() {
|
|
||||||
return free_chunks_total_words() * BytesPerWord;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update internal accounting after a chunk was added
|
// Update internal accounting after a chunk was added
|
||||||
void ChunkManager::account_for_added_chunk(const Metachunk* c) {
|
void ChunkManager::account_for_added_chunk(const Metachunk* c) {
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
|
@ -216,19 +215,6 @@ void ChunkManager::account_for_removed_chunk(const Metachunk* c) {
|
||||||
_free_chunks_total -= c->word_size();
|
_free_chunks_total -= c->word_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t ChunkManager::free_chunks_count() {
|
|
||||||
#ifdef ASSERT
|
|
||||||
if (!UseConcMarkSweepGC && !MetaspaceExpand_lock->is_locked()) {
|
|
||||||
MutexLockerEx cl(MetaspaceExpand_lock,
|
|
||||||
Mutex::_no_safepoint_check_flag);
|
|
||||||
// This lock is only needed in debug because the verification
|
|
||||||
// of the _free_chunks_totals walks the list of free chunks
|
|
||||||
slow_locked_verify_free_chunks_count();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return _free_chunks_count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkIndex ChunkManager::list_index(size_t size) {
|
ChunkIndex ChunkManager::list_index(size_t size) {
|
||||||
return get_chunk_type_by_size(size, is_class());
|
return get_chunk_type_by_size(size, is_class());
|
||||||
}
|
}
|
||||||
|
@ -239,43 +225,48 @@ size_t ChunkManager::size_by_index(ChunkIndex index) const {
|
||||||
return get_size_for_nonhumongous_chunktype(index, is_class());
|
return get_size_for_nonhumongous_chunktype(index, is_class());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::locked_verify_free_chunks_total() {
|
#ifdef ASSERT
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
void ChunkManager::verify(bool slow) const {
|
||||||
assert(sum_free_chunks() == _free_chunks_total,
|
|
||||||
"_free_chunks_total " SIZE_FORMAT " is not the"
|
|
||||||
" same as sum " SIZE_FORMAT, _free_chunks_total,
|
|
||||||
sum_free_chunks());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChunkManager::locked_verify_free_chunks_count() {
|
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
|
||||||
assert(sum_free_chunks_count() == _free_chunks_count,
|
|
||||||
"_free_chunks_count " SIZE_FORMAT " is not the"
|
|
||||||
" same as sum " SIZE_FORMAT, _free_chunks_count,
|
|
||||||
sum_free_chunks_count());
|
|
||||||
}
|
|
||||||
|
|
||||||
void ChunkManager::verify() {
|
|
||||||
MutexLockerEx cl(MetaspaceExpand_lock,
|
MutexLockerEx cl(MetaspaceExpand_lock,
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
locked_verify();
|
locked_verify(slow);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::locked_verify() {
|
void ChunkManager::locked_verify(bool slow) const {
|
||||||
locked_verify_free_chunks_count();
|
log_trace(gc, metaspace, freelist)("verifying %s chunkmanager (%s).",
|
||||||
locked_verify_free_chunks_total();
|
(is_class() ? "class space" : "metaspace"), (slow ? "slow" : "quick"));
|
||||||
|
|
||||||
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
|
|
||||||
|
size_t chunks_counted = 0;
|
||||||
|
size_t wordsize_chunks_counted = 0;
|
||||||
for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
|
for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
|
||||||
ChunkList* list = free_chunks(i);
|
const ChunkList* list = _free_chunks + i;
|
||||||
if (list != NULL) {
|
if (list != NULL) {
|
||||||
Metachunk* chunk = list->head();
|
Metachunk* chunk = list->head();
|
||||||
while (chunk) {
|
while (chunk) {
|
||||||
DEBUG_ONLY(do_verify_chunk(chunk);)
|
if (slow) {
|
||||||
|
do_verify_chunk(chunk);
|
||||||
|
}
|
||||||
assert(chunk->is_tagged_free(), "Chunk should be tagged as free.");
|
assert(chunk->is_tagged_free(), "Chunk should be tagged as free.");
|
||||||
|
chunks_counted ++;
|
||||||
|
wordsize_chunks_counted += chunk->size();
|
||||||
chunk = chunk->next();
|
chunk = chunk->next();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
chunks_counted += humongous_dictionary()->total_free_blocks();
|
||||||
|
wordsize_chunks_counted += humongous_dictionary()->total_size();
|
||||||
|
|
||||||
|
assert(chunks_counted == _free_chunks_count && wordsize_chunks_counted == _free_chunks_total,
|
||||||
|
"freelist accounting mismatch: "
|
||||||
|
"we think: " SIZE_FORMAT " chunks, total " SIZE_FORMAT " words, "
|
||||||
|
"reality: " SIZE_FORMAT " chunks, total " SIZE_FORMAT " words.",
|
||||||
|
_free_chunks_count, _free_chunks_total,
|
||||||
|
chunks_counted, wordsize_chunks_counted);
|
||||||
}
|
}
|
||||||
|
#endif // ASSERT
|
||||||
|
|
||||||
void ChunkManager::locked_print_free_chunks(outputStream* st) {
|
void ChunkManager::locked_print_free_chunks(outputStream* st) {
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
|
@ -283,51 +274,12 @@ void ChunkManager::locked_print_free_chunks(outputStream* st) {
|
||||||
_free_chunks_total, _free_chunks_count);
|
_free_chunks_total, _free_chunks_count);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::locked_print_sum_free_chunks(outputStream* st) {
|
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
|
||||||
st->print_cr("Sum free chunk total " SIZE_FORMAT " count " SIZE_FORMAT,
|
|
||||||
sum_free_chunks(), sum_free_chunks_count());
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
|
ChunkList* ChunkManager::free_chunks(ChunkIndex index) {
|
||||||
assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex,
|
assert(index == SpecializedIndex || index == SmallIndex || index == MediumIndex,
|
||||||
"Bad index: %d", (int)index);
|
"Bad index: %d", (int)index);
|
||||||
|
|
||||||
return &_free_chunks[index];
|
return &_free_chunks[index];
|
||||||
}
|
}
|
||||||
|
|
||||||
// These methods that sum the free chunk lists are used in printing
|
|
||||||
// methods that are used in product builds.
|
|
||||||
size_t ChunkManager::sum_free_chunks() {
|
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
|
||||||
size_t result = 0;
|
|
||||||
for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
|
|
||||||
ChunkList* list = free_chunks(i);
|
|
||||||
|
|
||||||
if (list == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = result + list->count() * list->size();
|
|
||||||
}
|
|
||||||
result = result + humongous_dictionary()->total_size();
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t ChunkManager::sum_free_chunks_count() {
|
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
|
||||||
size_t count = 0;
|
|
||||||
for (ChunkIndex i = ZeroIndex; i < NumberOfFreeLists; i = next_chunk_index(i)) {
|
|
||||||
ChunkList* list = free_chunks(i);
|
|
||||||
if (list == NULL) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
count = count + list->count();
|
|
||||||
}
|
|
||||||
count = count + humongous_dictionary()->total_free_blocks();
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
|
|
||||||
ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) {
|
ChunkList* ChunkManager::find_free_chunks_list(size_t word_size) {
|
||||||
ChunkIndex index = list_index(word_size);
|
ChunkIndex index = list_index(word_size);
|
||||||
assert(index < HumongousIndex, "No humongous list");
|
assert(index < HumongousIndex, "No humongous list");
|
||||||
|
@ -427,14 +379,18 @@ Metachunk* ChunkManager::split_chunk(size_t target_chunk_word_size, Metachunk* l
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Note: at this point, the VirtualSpaceNode is invalid since we split a chunk and
|
||||||
|
// did not yet hand out part of that split; so, vsn->verify_free_chunks_are_ideally_merged()
|
||||||
|
// would assert. Instead, do all verifications in the caller.
|
||||||
|
|
||||||
|
DEBUG_ONLY(g_internal_statistics.num_chunk_splits ++);
|
||||||
|
|
||||||
return target_chunk;
|
return target_chunk;
|
||||||
}
|
}
|
||||||
|
|
||||||
Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
|
Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
|
|
||||||
slow_locked_verify();
|
|
||||||
|
|
||||||
Metachunk* chunk = NULL;
|
Metachunk* chunk = NULL;
|
||||||
bool we_did_split_a_chunk = false;
|
bool we_did_split_a_chunk = false;
|
||||||
|
|
||||||
|
@ -524,14 +480,19 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
|
||||||
|
|
||||||
// Run some verifications (some more if we did a chunk split)
|
// Run some verifications (some more if we did a chunk split)
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
if (VerifyMetaspace) {
|
|
||||||
locked_verify();
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
// Be extra verify-y when chunk split happened.
|
||||||
|
locked_verify(true);
|
||||||
VirtualSpaceNode* const vsn = chunk->container();
|
VirtualSpaceNode* const vsn = chunk->container();
|
||||||
vsn->verify();
|
vsn->verify(true);
|
||||||
if (we_did_split_a_chunk) {
|
if (we_did_split_a_chunk) {
|
||||||
vsn->verify_free_chunks_are_ideally_merged();
|
vsn->verify_free_chunks_are_ideally_merged();
|
||||||
}
|
}
|
||||||
}
|
END_EVERY_NTH
|
||||||
|
|
||||||
|
g_internal_statistics.num_chunks_removed_from_freelist ++;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return chunk;
|
return chunk;
|
||||||
|
@ -539,7 +500,6 @@ Metachunk* ChunkManager::free_chunks_get(size_t word_size) {
|
||||||
|
|
||||||
Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
|
Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
slow_locked_verify();
|
|
||||||
|
|
||||||
// Take from the beginning of the list
|
// Take from the beginning of the list
|
||||||
Metachunk* chunk = free_chunks_get(word_size);
|
Metachunk* chunk = free_chunks_get(word_size);
|
||||||
|
@ -570,9 +530,17 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::return_single_chunk(Metachunk* chunk) {
|
void ChunkManager::return_single_chunk(Metachunk* chunk) {
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
this->locked_verify(false);
|
||||||
|
do_verify_chunk(chunk);
|
||||||
|
END_EVERY_NTH
|
||||||
|
#endif
|
||||||
|
|
||||||
const ChunkIndex index = chunk->get_chunk_type();
|
const ChunkIndex index = chunk->get_chunk_type();
|
||||||
assert_lock_strong(MetaspaceExpand_lock);
|
assert_lock_strong(MetaspaceExpand_lock);
|
||||||
DEBUG_ONLY(do_verify_chunk(chunk);)
|
DEBUG_ONLY(g_internal_statistics.num_chunks_added_to_freelist ++;)
|
||||||
assert(chunk != NULL, "Expected chunk.");
|
assert(chunk != NULL, "Expected chunk.");
|
||||||
assert(chunk->container() != NULL, "Container should have been set.");
|
assert(chunk->container() != NULL, "Container should have been set.");
|
||||||
assert(chunk->is_tagged_free() == false, "Chunk should be in use.");
|
assert(chunk->is_tagged_free() == false, "Chunk should be in use.");
|
||||||
|
@ -583,6 +551,9 @@ void ChunkManager::return_single_chunk(Metachunk* chunk) {
|
||||||
// keeps tree node pointers in the chunk payload area which mangle will overwrite.
|
// keeps tree node pointers in the chunk payload area which mangle will overwrite.
|
||||||
DEBUG_ONLY(chunk->mangle(badMetaWordVal);)
|
DEBUG_ONLY(chunk->mangle(badMetaWordVal);)
|
||||||
|
|
||||||
|
// may need node for verification later after chunk may have been merged away.
|
||||||
|
DEBUG_ONLY(VirtualSpaceNode* vsn = chunk->container(); )
|
||||||
|
|
||||||
if (index != HumongousIndex) {
|
if (index != HumongousIndex) {
|
||||||
// Return non-humongous chunk to freelist.
|
// Return non-humongous chunk to freelist.
|
||||||
ChunkList* list = free_chunks(index);
|
ChunkList* list = free_chunks(index);
|
||||||
|
@ -618,6 +589,16 @@ void ChunkManager::return_single_chunk(Metachunk* chunk) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// From here on do not access chunk anymore, it may have been merged with another chunk.
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
this->locked_verify(true);
|
||||||
|
vsn->verify(true);
|
||||||
|
vsn->verify_free_chunks_are_ideally_merged();
|
||||||
|
END_EVERY_NTH
|
||||||
|
#endif
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ChunkManager::return_chunk_list(Metachunk* chunks) {
|
void ChunkManager::return_chunk_list(Metachunk* chunks) {
|
||||||
|
|
|
@ -33,7 +33,7 @@
|
||||||
#include "memory/metaspaceChunkFreeListSummary.hpp"
|
#include "memory/metaspaceChunkFreeListSummary.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
class ChunkManagerTest;
|
class ChunkManagerTestAccessor;
|
||||||
|
|
||||||
namespace metaspace {
|
namespace metaspace {
|
||||||
|
|
||||||
|
@ -42,7 +42,7 @@ typedef BinaryTreeDictionary<Metachunk, FreeList<Metachunk> > ChunkTreeDictionar
|
||||||
|
|
||||||
// Manages the global free lists of chunks.
|
// Manages the global free lists of chunks.
|
||||||
class ChunkManager : public CHeapObj<mtInternal> {
|
class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
friend class ::ChunkManagerTest;
|
friend class ::ChunkManagerTestAccessor;
|
||||||
|
|
||||||
// Free list of chunks of different sizes.
|
// Free list of chunks of different sizes.
|
||||||
// SpecializedChunk
|
// SpecializedChunk
|
||||||
|
@ -63,9 +63,8 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
ChunkTreeDictionary _humongous_dictionary;
|
ChunkTreeDictionary _humongous_dictionary;
|
||||||
|
|
||||||
// Returns the humongous chunk dictionary.
|
// Returns the humongous chunk dictionary.
|
||||||
ChunkTreeDictionary* humongous_dictionary() {
|
ChunkTreeDictionary* humongous_dictionary() { return &_humongous_dictionary; }
|
||||||
return &_humongous_dictionary;
|
const ChunkTreeDictionary* humongous_dictionary() const { return &_humongous_dictionary; }
|
||||||
}
|
|
||||||
|
|
||||||
// Size, in metaspace words, of all chunks managed by this ChunkManager
|
// Size, in metaspace words, of all chunks managed by this ChunkManager
|
||||||
size_t _free_chunks_total;
|
size_t _free_chunks_total;
|
||||||
|
@ -76,22 +75,6 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
void account_for_added_chunk(const Metachunk* c);
|
void account_for_added_chunk(const Metachunk* c);
|
||||||
void account_for_removed_chunk(const Metachunk* c);
|
void account_for_removed_chunk(const Metachunk* c);
|
||||||
|
|
||||||
size_t sum_free_chunks();
|
|
||||||
size_t sum_free_chunks_count();
|
|
||||||
|
|
||||||
void locked_verify_free_chunks_total();
|
|
||||||
void slow_locked_verify_free_chunks_total() {
|
|
||||||
if (VerifyMetaspace) {
|
|
||||||
locked_verify_free_chunks_total();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
void locked_verify_free_chunks_count();
|
|
||||||
void slow_locked_verify_free_chunks_count() {
|
|
||||||
if (VerifyMetaspace) {
|
|
||||||
locked_verify_free_chunks_count();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Given a pointer to a chunk, attempts to merge it with neighboring
|
// Given a pointer to a chunk, attempts to merge it with neighboring
|
||||||
// free chunks to form a bigger chunk. Returns true if successful.
|
// free chunks to form a bigger chunk. Returns true if successful.
|
||||||
bool attempt_to_coalesce_around_chunk(Metachunk* chunk, ChunkIndex target_chunk_type);
|
bool attempt_to_coalesce_around_chunk(Metachunk* chunk, ChunkIndex target_chunk_type);
|
||||||
|
@ -147,11 +130,11 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
void return_chunk_list(Metachunk* chunk);
|
void return_chunk_list(Metachunk* chunk);
|
||||||
|
|
||||||
// Total of the space in the free chunks list
|
// Total of the space in the free chunks list
|
||||||
size_t free_chunks_total_words();
|
size_t free_chunks_total_words() const { return _free_chunks_total; }
|
||||||
size_t free_chunks_total_bytes();
|
size_t free_chunks_total_bytes() const { return free_chunks_total_words() * BytesPerWord; }
|
||||||
|
|
||||||
// Number of chunks in the free chunks list
|
// Number of chunks in the free chunks list
|
||||||
size_t free_chunks_count();
|
size_t free_chunks_count() const { return _free_chunks_count; }
|
||||||
|
|
||||||
// Remove from a list by size. Selects list based on size of chunk.
|
// Remove from a list by size. Selects list based on size of chunk.
|
||||||
Metachunk* free_chunks_get(size_t chunk_word_size);
|
Metachunk* free_chunks_get(size_t chunk_word_size);
|
||||||
|
@ -195,22 +178,14 @@ class ChunkManager : public CHeapObj<mtInternal> {
|
||||||
size_free_chunks_in_bytes(HumongousIndex));
|
size_free_chunks_in_bytes(HumongousIndex));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
// Debug support
|
// Debug support
|
||||||
void verify();
|
// Verify free list integrity. slow=true: verify chunk-internal integrity too.
|
||||||
void slow_verify() {
|
void verify(bool slow) const;
|
||||||
if (VerifyMetaspace) {
|
void locked_verify(bool slow) const;
|
||||||
verify();
|
#endif
|
||||||
}
|
|
||||||
}
|
|
||||||
void locked_verify();
|
|
||||||
void slow_locked_verify() {
|
|
||||||
if (VerifyMetaspace) {
|
|
||||||
locked_verify();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void locked_print_free_chunks(outputStream* st);
|
void locked_print_free_chunks(outputStream* st);
|
||||||
void locked_print_sum_free_chunks(outputStream* st);
|
|
||||||
|
|
||||||
// Fill in current statistic values to the given statistics object.
|
// Fill in current statistic values to the given statistics object.
|
||||||
void collect_statistics(ChunkManagerStatistics* out) const;
|
void collect_statistics(ChunkManagerStatistics* out) const;
|
||||||
|
|
|
@ -41,6 +41,17 @@ class Metadebug : AllStatic {
|
||||||
#endif
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
#define EVERY_NTH(n) \
|
||||||
|
{ static int counter_ = 0; \
|
||||||
|
if (n > 0) { \
|
||||||
|
counter_ ++; \
|
||||||
|
if (counter_ > n) { \
|
||||||
|
counter_ = 0; \
|
||||||
|
|
||||||
|
#define END_EVERY_NTH } } }
|
||||||
|
#endif // ASSERT
|
||||||
|
|
||||||
} // namespace metaspace
|
} // namespace metaspace
|
||||||
|
|
||||||
#endif // SHARE_MEMORY_METASPACE_METADEBUG_HPP
|
#endif // SHARE_MEMORY_METASPACE_METADEBUG_HPP
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#ifndef SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP
|
#ifndef SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP
|
||||||
#define SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP
|
#define SHARE_MEMORY_METASPACE_METASPACECOMMON_HPP
|
||||||
|
|
||||||
|
#include "utilities/align.hpp"
|
||||||
#include "utilities/debug.hpp"
|
#include "utilities/debug.hpp"
|
||||||
#include "utilities/globalDefinitions.hpp"
|
#include "utilities/globalDefinitions.hpp"
|
||||||
|
|
||||||
|
@ -85,6 +86,14 @@ struct internal_statistics_t {
|
||||||
uintx num_external_deallocs;
|
uintx num_external_deallocs;
|
||||||
// Number of times an allocation was satisfied from deallocated blocks.
|
// Number of times an allocation was satisfied from deallocated blocks.
|
||||||
uintx num_allocs_from_deallocated_blocks;
|
uintx num_allocs_from_deallocated_blocks;
|
||||||
|
// Number of times a chunk was added to the freelist
|
||||||
|
uintx num_chunks_added_to_freelist;
|
||||||
|
// Number of times a chunk was removed from the freelist
|
||||||
|
uintx num_chunks_removed_from_freelist;
|
||||||
|
// Number of chunk merges
|
||||||
|
uintx num_chunk_merges;
|
||||||
|
// Number of chunk splits
|
||||||
|
uintx num_chunk_splits;
|
||||||
};
|
};
|
||||||
extern internal_statistics_t g_internal_statistics;
|
extern internal_statistics_t g_internal_statistics;
|
||||||
#endif
|
#endif
|
||||||
|
@ -111,6 +120,16 @@ ChunkIndex prev_chunk_index(ChunkIndex i);
|
||||||
// Returns a descriptive name for a chunk type.
|
// Returns a descriptive name for a chunk type.
|
||||||
const char* chunk_size_name(ChunkIndex index);
|
const char* chunk_size_name(ChunkIndex index);
|
||||||
|
|
||||||
|
// Verify chunk sizes.
|
||||||
|
inline bool is_valid_chunksize(bool is_class, size_t size) {
|
||||||
|
const size_t reasonable_maximum_humongous_chunk_size = 1 * G;
|
||||||
|
return is_aligned(size, sizeof(MetaWord)) &&
|
||||||
|
size < reasonable_maximum_humongous_chunk_size &&
|
||||||
|
is_class ?
|
||||||
|
(size == ClassSpecializedChunk || size == ClassSmallChunk || size >= ClassMediumChunk) :
|
||||||
|
(size == SpecializedChunk || size == SmallChunk || size >= MediumChunk);
|
||||||
|
}
|
||||||
|
|
||||||
// Verify chunk type.
|
// Verify chunk type.
|
||||||
inline bool is_valid_chunktype(ChunkIndex index) {
|
inline bool is_valid_chunktype(ChunkIndex index) {
|
||||||
return index == SpecializedIndex || index == SmallIndex ||
|
return index == SpecializedIndex || index == SmallIndex ||
|
||||||
|
|
|
@ -287,8 +287,6 @@ SpaceManager::~SpaceManager() {
|
||||||
MutexLockerEx fcl(MetaspaceExpand_lock,
|
MutexLockerEx fcl(MetaspaceExpand_lock,
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
|
|
||||||
chunk_manager()->slow_locked_verify();
|
|
||||||
|
|
||||||
account_for_spacemanager_death();
|
account_for_spacemanager_death();
|
||||||
|
|
||||||
Log(gc, metaspace, freelist) log;
|
Log(gc, metaspace, freelist) log;
|
||||||
|
@ -313,7 +311,11 @@ SpaceManager::~SpaceManager() {
|
||||||
_current_chunk = NULL;
|
_current_chunk = NULL;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
chunk_manager()->slow_locked_verify();
|
#ifdef ASSERT
|
||||||
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
chunk_manager()->locked_verify(true);
|
||||||
|
END_EVERY_NTH
|
||||||
|
#endif
|
||||||
|
|
||||||
if (_block_freelists != NULL) {
|
if (_block_freelists != NULL) {
|
||||||
delete _block_freelists;
|
delete _block_freelists;
|
||||||
|
@ -405,8 +407,6 @@ MetaWord* SpaceManager::allocate(size_t word_size) {
|
||||||
BlockFreelist* fl = block_freelists();
|
BlockFreelist* fl = block_freelists();
|
||||||
MetaWord* p = NULL;
|
MetaWord* p = NULL;
|
||||||
|
|
||||||
DEBUG_ONLY(if (VerifyMetaspace) verify_metrics_locked());
|
|
||||||
|
|
||||||
// Allocation from the dictionary is expensive in the sense that
|
// Allocation from the dictionary is expensive in the sense that
|
||||||
// the dictionary has to be searched for a size. Don't allocate
|
// the dictionary has to be searched for a size. Don't allocate
|
||||||
// from the dictionary until it starts to get fat. Is this
|
// from the dictionary until it starts to get fat. Is this
|
||||||
|
@ -422,6 +422,12 @@ MetaWord* SpaceManager::allocate(size_t word_size) {
|
||||||
p = allocate_work(raw_word_size);
|
p = allocate_work(raw_word_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
verify_metrics_locked();
|
||||||
|
END_EVERY_NTH
|
||||||
|
#endif
|
||||||
|
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -97,7 +97,7 @@ void VirtualSpaceList::purge(ChunkManager* chunk_manager) {
|
||||||
VirtualSpaceNode* next_vsl = prev_vsl;
|
VirtualSpaceNode* next_vsl = prev_vsl;
|
||||||
while (next_vsl != NULL) {
|
while (next_vsl != NULL) {
|
||||||
VirtualSpaceNode* vsl = next_vsl;
|
VirtualSpaceNode* vsl = next_vsl;
|
||||||
DEBUG_ONLY(vsl->verify_container_count();)
|
DEBUG_ONLY(vsl->verify(false);)
|
||||||
next_vsl = vsl->next();
|
next_vsl = vsl->next();
|
||||||
// Don't free the current virtual space since it will likely
|
// Don't free the current virtual space since it will likely
|
||||||
// be needed soon.
|
// be needed soon.
|
||||||
|
|
|
@ -29,6 +29,7 @@
|
||||||
#include "memory/metaspace/metachunk.hpp"
|
#include "memory/metaspace/metachunk.hpp"
|
||||||
#include "memory/metaspace.hpp"
|
#include "memory/metaspace.hpp"
|
||||||
#include "memory/metaspace/chunkManager.hpp"
|
#include "memory/metaspace/chunkManager.hpp"
|
||||||
|
#include "memory/metaspace/metaDebug.hpp"
|
||||||
#include "memory/metaspace/metaspaceCommon.hpp"
|
#include "memory/metaspace/metaspaceCommon.hpp"
|
||||||
#include "memory/metaspace/occupancyMap.hpp"
|
#include "memory/metaspace/occupancyMap.hpp"
|
||||||
#include "memory/metaspace/virtualSpaceNode.hpp"
|
#include "memory/metaspace/virtualSpaceNode.hpp"
|
||||||
|
@ -73,7 +74,8 @@ VirtualSpaceNode::VirtualSpaceNode(bool is_class, size_t bytes) :
|
||||||
}
|
}
|
||||||
|
|
||||||
void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
|
void VirtualSpaceNode::purge(ChunkManager* chunk_manager) {
|
||||||
DEBUG_ONLY(this->verify();)
|
// When a node is purged, lets give it a thorough examination.
|
||||||
|
DEBUG_ONLY(verify(true);)
|
||||||
Metachunk* chunk = first_chunk();
|
Metachunk* chunk = first_chunk();
|
||||||
Metachunk* invalid_chunk = (Metachunk*) top();
|
Metachunk* invalid_chunk = (Metachunk*) top();
|
||||||
while (chunk < invalid_chunk ) {
|
while (chunk < invalid_chunk ) {
|
||||||
|
@ -171,49 +173,39 @@ void VirtualSpaceNode::print_map(outputStream* st, bool is_class) const {
|
||||||
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
uintx VirtualSpaceNode::container_count_slow() {
|
|
||||||
uintx count = 0;
|
|
||||||
Metachunk* chunk = first_chunk();
|
|
||||||
Metachunk* invalid_chunk = (Metachunk*) top();
|
|
||||||
while (chunk < invalid_chunk ) {
|
|
||||||
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
|
||||||
do_verify_chunk(chunk);
|
|
||||||
// Don't count the chunks on the free lists. Those are
|
|
||||||
// still part of the VirtualSpaceNode but not currently
|
|
||||||
// counted.
|
|
||||||
if (!chunk->is_tagged_free()) {
|
|
||||||
count++;
|
|
||||||
}
|
|
||||||
chunk = (Metachunk*) next;
|
|
||||||
}
|
|
||||||
return count;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
// Verify counters, all chunks in this list node and the occupancy map.
|
// Verify counters, all chunks in this list node and the occupancy map.
|
||||||
void VirtualSpaceNode::verify() {
|
void VirtualSpaceNode::verify(bool slow) {
|
||||||
|
log_trace(gc, metaspace, freelist)("verifying %s virtual space node (%s).",
|
||||||
|
(is_class() ? "class space" : "metaspace"), (slow ? "slow" : "quick"));
|
||||||
|
// Fast mode: just verify chunk counters and basic geometry
|
||||||
|
// Slow mode: verify chunks and occupancy map
|
||||||
uintx num_in_use_chunks = 0;
|
uintx num_in_use_chunks = 0;
|
||||||
Metachunk* chunk = first_chunk();
|
Metachunk* chunk = first_chunk();
|
||||||
Metachunk* invalid_chunk = (Metachunk*) top();
|
Metachunk* invalid_chunk = (Metachunk*) top();
|
||||||
|
|
||||||
// Iterate the chunks in this node and verify each chunk.
|
// Iterate the chunks in this node and verify each chunk.
|
||||||
while (chunk < invalid_chunk ) {
|
while (chunk < invalid_chunk ) {
|
||||||
DEBUG_ONLY(do_verify_chunk(chunk);)
|
if (slow) {
|
||||||
|
do_verify_chunk(chunk);
|
||||||
|
}
|
||||||
if (!chunk->is_tagged_free()) {
|
if (!chunk->is_tagged_free()) {
|
||||||
num_in_use_chunks ++;
|
num_in_use_chunks ++;
|
||||||
}
|
}
|
||||||
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
const size_t s = chunk->word_size();
|
||||||
|
// Prevent endless loop on invalid chunk size.
|
||||||
|
assert(is_valid_chunksize(is_class(), s), "Invalid chunk size: " SIZE_FORMAT ".", s);
|
||||||
|
MetaWord* next = ((MetaWord*)chunk) + s;
|
||||||
chunk = (Metachunk*) next;
|
chunk = (Metachunk*) next;
|
||||||
}
|
}
|
||||||
assert(_container_count == num_in_use_chunks, "Container count mismatch (real: " UINTX_FORMAT
|
assert(_container_count == num_in_use_chunks, "Container count mismatch (real: " UINTX_FORMAT
|
||||||
", counter: " UINTX_FORMAT ".", num_in_use_chunks, _container_count);
|
", counter: " UINTX_FORMAT ".", num_in_use_chunks, _container_count);
|
||||||
// Also verify the occupancy map.
|
// Also verify the occupancy map.
|
||||||
occupancy_map()->verify(this->bottom(), this->top());
|
if (slow) {
|
||||||
|
occupancy_map()->verify(bottom(), top());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
#endif // ASSERT
|
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
// Verify that all free chunks in this node are ideally merged
|
// Verify that all free chunks in this node are ideally merged
|
||||||
// (there not should be multiple small chunks where a large chunk could exist.)
|
// (there not should be multiple small chunks where a large chunk could exist.)
|
||||||
void VirtualSpaceNode::verify_free_chunks_are_ideally_merged() {
|
void VirtualSpaceNode::verify_free_chunks_are_ideally_merged() {
|
||||||
|
@ -224,23 +216,31 @@ void VirtualSpaceNode::verify_free_chunks_are_ideally_merged() {
|
||||||
const size_t size_small = (is_class() ? ClassSmallChunk : SmallChunk) * BytesPerWord;
|
const size_t size_small = (is_class() ? ClassSmallChunk : SmallChunk) * BytesPerWord;
|
||||||
int num_free_chunks_since_last_med_boundary = -1;
|
int num_free_chunks_since_last_med_boundary = -1;
|
||||||
int num_free_chunks_since_last_small_boundary = -1;
|
int num_free_chunks_since_last_small_boundary = -1;
|
||||||
while (chunk < invalid_chunk ) {
|
bool error = false;
|
||||||
|
char err[256];
|
||||||
|
while (!error && chunk < invalid_chunk ) {
|
||||||
// Test for missed chunk merge opportunities: count number of free chunks since last chunk boundary.
|
// Test for missed chunk merge opportunities: count number of free chunks since last chunk boundary.
|
||||||
// Reset the counter when encountering a non-free chunk.
|
// Reset the counter when encountering a non-free chunk.
|
||||||
if (chunk->get_chunk_type() != HumongousIndex) {
|
if (chunk->get_chunk_type() != HumongousIndex) {
|
||||||
if (chunk->is_tagged_free()) {
|
if (chunk->is_tagged_free()) {
|
||||||
// Count successive free, non-humongous chunks.
|
// Count successive free, non-humongous chunks.
|
||||||
if (is_aligned(chunk, size_small)) {
|
if (is_aligned(chunk, size_small)) {
|
||||||
assert(num_free_chunks_since_last_small_boundary <= 1,
|
if (num_free_chunks_since_last_small_boundary > 0) {
|
||||||
"Missed chunk merge opportunity at " PTR_FORMAT " for chunk size " SIZE_FORMAT_HEX ".", p2i(chunk) - size_small, size_small);
|
error = true;
|
||||||
|
jio_snprintf(err, sizeof(err), "Missed chunk merge opportunity to merge a small chunk preceding " PTR_FORMAT ".", p2i(chunk));
|
||||||
|
} else {
|
||||||
num_free_chunks_since_last_small_boundary = 0;
|
num_free_chunks_since_last_small_boundary = 0;
|
||||||
|
}
|
||||||
} else if (num_free_chunks_since_last_small_boundary != -1) {
|
} else if (num_free_chunks_since_last_small_boundary != -1) {
|
||||||
num_free_chunks_since_last_small_boundary ++;
|
num_free_chunks_since_last_small_boundary ++;
|
||||||
}
|
}
|
||||||
if (is_aligned(chunk, size_med)) {
|
if (is_aligned(chunk, size_med)) {
|
||||||
assert(num_free_chunks_since_last_med_boundary <= 1,
|
if (num_free_chunks_since_last_med_boundary > 0) {
|
||||||
"Missed chunk merge opportunity at " PTR_FORMAT " for chunk size " SIZE_FORMAT_HEX ".", p2i(chunk) - size_med, size_med);
|
error = true;
|
||||||
|
jio_snprintf(err, sizeof(err), "Missed chunk merge opportunity to merge a medium chunk preceding " PTR_FORMAT ".", p2i(chunk));
|
||||||
|
} else {
|
||||||
num_free_chunks_since_last_med_boundary = 0;
|
num_free_chunks_since_last_med_boundary = 0;
|
||||||
|
}
|
||||||
} else if (num_free_chunks_since_last_med_boundary != -1) {
|
} else if (num_free_chunks_since_last_med_boundary != -1) {
|
||||||
num_free_chunks_since_last_med_boundary ++;
|
num_free_chunks_since_last_med_boundary ++;
|
||||||
}
|
}
|
||||||
|
@ -255,6 +255,11 @@ void VirtualSpaceNode::verify_free_chunks_are_ideally_merged() {
|
||||||
num_free_chunks_since_last_small_boundary = -1;
|
num_free_chunks_since_last_small_boundary = -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (error) {
|
||||||
|
print_map(tty, is_class());
|
||||||
|
fatal("%s", err);
|
||||||
|
}
|
||||||
|
|
||||||
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
MetaWord* next = ((MetaWord*)chunk) + chunk->word_size();
|
||||||
chunk = (Metachunk*) next;
|
chunk = (Metachunk*) next;
|
||||||
}
|
}
|
||||||
|
@ -271,14 +276,6 @@ void VirtualSpaceNode::dec_container_count() {
|
||||||
_container_count--;
|
_container_count--;
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef ASSERT
|
|
||||||
void VirtualSpaceNode::verify_container_count() {
|
|
||||||
assert(_container_count == container_count_slow(),
|
|
||||||
"Inconsistency in container_count _container_count " UINTX_FORMAT
|
|
||||||
" container_count_slow() " UINTX_FORMAT, _container_count, container_count_slow());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
VirtualSpaceNode::~VirtualSpaceNode() {
|
VirtualSpaceNode::~VirtualSpaceNode() {
|
||||||
_rs.release();
|
_rs.release();
|
||||||
if (_occupancy_map != NULL) {
|
if (_occupancy_map != NULL) {
|
||||||
|
@ -309,7 +306,7 @@ void VirtualSpaceNode::allocate_padding_chunks_until_top_is_at(MetaWord* target_
|
||||||
assert(target_top > top(), "Sanity");
|
assert(target_top > top(), "Sanity");
|
||||||
|
|
||||||
// Padding chunks are added to the freelist.
|
// Padding chunks are added to the freelist.
|
||||||
ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(this->is_class());
|
ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(is_class());
|
||||||
|
|
||||||
// shorthands
|
// shorthands
|
||||||
const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
|
const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
|
||||||
|
@ -378,7 +375,7 @@ Metachunk* VirtualSpaceNode::take_from_committed(size_t chunk_word_size) {
|
||||||
// chunks. These chunks are created and added to the freelist.
|
// chunks. These chunks are created and added to the freelist.
|
||||||
|
|
||||||
// The chunk manager to which we will give our padding chunks.
|
// The chunk manager to which we will give our padding chunks.
|
||||||
ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(this->is_class());
|
ChunkManager* const chunk_manager = Metaspace::get_chunk_manager(is_class());
|
||||||
|
|
||||||
// shorthands
|
// shorthands
|
||||||
const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
|
const size_t spec_word_size = chunk_manager->specialized_chunk_word_size();
|
||||||
|
@ -450,12 +447,13 @@ Metachunk* VirtualSpaceNode::take_from_committed(size_t chunk_word_size) {
|
||||||
|
|
||||||
inc_container_count();
|
inc_container_count();
|
||||||
|
|
||||||
if (VerifyMetaspace) {
|
#ifdef ASSERT
|
||||||
DEBUG_ONLY(chunk_manager->locked_verify());
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
DEBUG_ONLY(this->verify());
|
chunk_manager->locked_verify(true);
|
||||||
}
|
verify(true);
|
||||||
|
END_EVERY_NTH
|
||||||
DEBUG_ONLY(do_verify_chunk(result));
|
do_verify_chunk(result);
|
||||||
|
#endif
|
||||||
|
|
||||||
result->inc_use_count();
|
result->inc_use_count();
|
||||||
|
|
||||||
|
@ -558,8 +556,13 @@ void VirtualSpaceNode::mangle() {
|
||||||
#endif // ASSERT
|
#endif // ASSERT
|
||||||
|
|
||||||
void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
|
void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
|
||||||
DEBUG_ONLY(verify_container_count();)
|
assert(is_class() == chunk_manager->is_class(), "Wrong ChunkManager?");
|
||||||
assert(this->is_class() == chunk_manager->is_class(), "Wrong ChunkManager?");
|
#ifdef ASSERT
|
||||||
|
verify(false);
|
||||||
|
EVERY_NTH(VerifyMetaspaceInterval)
|
||||||
|
verify(true);
|
||||||
|
END_EVERY_NTH
|
||||||
|
#endif
|
||||||
for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) {
|
for (int i = (int)MediumIndex; i >= (int)ZeroIndex; --i) {
|
||||||
ChunkIndex index = (ChunkIndex)i;
|
ChunkIndex index = (ChunkIndex)i;
|
||||||
size_t chunk_size = chunk_manager->size_by_index(index);
|
size_t chunk_size = chunk_manager->size_by_index(index);
|
||||||
|
@ -577,7 +580,6 @@ void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
|
||||||
}
|
}
|
||||||
chunk_manager->return_single_chunk(chunk);
|
chunk_manager->return_single_chunk(chunk);
|
||||||
}
|
}
|
||||||
DEBUG_ONLY(verify_container_count();)
|
|
||||||
}
|
}
|
||||||
assert(free_words_in_vs() == 0, "should be empty now");
|
assert(free_words_in_vs() == 0, "should be empty now");
|
||||||
}
|
}
|
||||||
|
|
|
@ -115,10 +115,6 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
|
||||||
uintx container_count() { return _container_count; }
|
uintx container_count() { return _container_count; }
|
||||||
void inc_container_count();
|
void inc_container_count();
|
||||||
void dec_container_count();
|
void dec_container_count();
|
||||||
#ifdef ASSERT
|
|
||||||
uintx container_count_slow();
|
|
||||||
void verify_container_count();
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// used and capacity in this single entry in the list
|
// used and capacity in this single entry in the list
|
||||||
size_t used_words_in_vs() const;
|
size_t used_words_in_vs() const;
|
||||||
|
@ -152,10 +148,10 @@ class VirtualSpaceNode : public CHeapObj<mtClass> {
|
||||||
|
|
||||||
// Debug support
|
// Debug support
|
||||||
DEBUG_ONLY(void mangle();)
|
DEBUG_ONLY(void mangle();)
|
||||||
// Verify counters, all chunks in this list node and the occupancy map.
|
// Verify counters and basic structure. Slow mode: verify all chunks in depth and occupancy map.
|
||||||
DEBUG_ONLY(void verify();)
|
DEBUG_ONLY(void verify(bool slow);)
|
||||||
// Verify that all free chunks in this node are ideally merged
|
// Verify that all free chunks in this node are ideally merged
|
||||||
// (there not should be multiple small chunks where a large chunk could exist.)
|
// (there should not be multiple small chunks where a large chunk could exist.)
|
||||||
DEBUG_ONLY(void verify_free_chunks_are_ideally_merged();)
|
DEBUG_ONLY(void verify_free_chunks_are_ideally_merged();)
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
|
@ -2525,8 +2525,9 @@ define_pd_global(uint64_t,MaxRAM, 1ULL*G);
|
||||||
"File of size Xmx is pre-allocated for performance reason, so" \
|
"File of size Xmx is pre-allocated for performance reason, so" \
|
||||||
"we need that much space available") \
|
"we need that much space available") \
|
||||||
\
|
\
|
||||||
develop(bool, VerifyMetaspace, false, \
|
develop(int, VerifyMetaspaceInterval, DEBUG_ONLY(500) NOT_DEBUG(0), \
|
||||||
"Verify metaspace on chunk movements.") \
|
"Run periodic metaspace verifications (0 - none, " \
|
||||||
|
"1 - always, >1 every nth interval)") \
|
||||||
\
|
\
|
||||||
diagnostic(bool, ShowRegistersOnAssert, true, \
|
diagnostic(bool, ShowRegistersOnAssert, true, \
|
||||||
"On internal errors, include registers in error report.") \
|
"On internal errors, include registers in error report.") \
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue