8202634: Metaspace: simplify SpaceManager lists

Reviewed-by: zgu, coleenp
This commit is contained in:
Thomas Stuefe 2018-05-09 06:51:41 +02:00
parent 3b3d16a6de
commit 85544dd1e4
3 changed files with 54 additions and 92 deletions

View File

@ -107,7 +107,7 @@ void Metachunk::mangle(juint word_value) {
Copy::fill_to_words(start, size, word_value);
}
void Metachunk::verify() {
void Metachunk::verify() const {
assert(is_valid_sentinel(), "Chunk " PTR_FORMAT ": sentinel invalid", p2i(this));
const ChunkIndex chunk_type = get_chunk_type();
assert(is_valid_chunktype(chunk_type), "Chunk " PTR_FORMAT ": Invalid chunk type.", p2i(this));

View File

@ -228,7 +228,7 @@ class Metachunk : public Metabase<Metachunk> {
bool is_class() const { return _is_class; }
DEBUG_ONLY(void mangle(juint word_value);)
DEBUG_ONLY(void verify();)
DEBUG_ONLY(void verify() const;)
};

View File

@ -299,11 +299,11 @@ class ChunkManager : public CHeapObj<mtInternal> {
void remove_chunk(Metachunk* chunk);
// Return a single chunk of type index to the ChunkManager.
void return_single_chunk(ChunkIndex index, Metachunk* chunk);
void return_single_chunk(Metachunk* chunk);
// Add the simple linked list of chunks to the freelist of chunks
// of type index.
void return_chunk_list(ChunkIndex index, Metachunk* chunk);
void return_chunk_list(Metachunk* chunks);
// Total of the space in the free chunks list
size_t free_chunks_total_words();
@ -1281,7 +1281,7 @@ class SpaceManager : public CHeapObj<mtClass> {
// List of chunks in use by this SpaceManager. Allocations
// are done from the current chunk. The list is used for deallocating
// chunks when the SpaceManager is freed.
Metachunk* _chunks_in_use[NumberOfInUseLists];
Metachunk* _chunk_list;
Metachunk* _current_chunk;
// Maximum number of small chunks to allocate to a SpaceManager
@ -1298,6 +1298,7 @@ class SpaceManager : public CHeapObj<mtClass> {
size_t _overhead_words;
size_t _capacity_words;
size_t _used_words;
uintx _num_chunks_by_type[NumberOfInUseLists];
// Free lists of blocks are per SpaceManager since they
// are assumed to be in chunks in use by the SpaceManager
@ -1307,10 +1308,7 @@ class SpaceManager : public CHeapObj<mtClass> {
private:
// Accessors
Metachunk* chunks_in_use(ChunkIndex index) const { return _chunks_in_use[index]; }
void set_chunks_in_use(ChunkIndex index, Metachunk* v) {
_chunks_in_use[index] = v;
}
Metachunk* chunk_list() const { return _chunk_list; }
BlockFreelist* block_freelists() const { return _block_freelists; }
@ -1338,9 +1336,6 @@ class SpaceManager : public CHeapObj<mtClass> {
// Verify internal counters against the current state. Expects to be locked with lock().
DEBUG_ONLY(void verify_metrics_locked() const;)
protected:
void initialize();
public:
SpaceManager(Metaspace::MetadataType mdtype,
Metaspace::MetaspaceType space_type,
@ -1393,7 +1388,7 @@ class SpaceManager : public CHeapObj<mtClass> {
size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const;
// Todo: remove this once we have counters by chunk type.
size_t sum_count_in_chunks_in_use(ChunkIndex i);
uintx num_chunks_by_type(ChunkIndex chunk_type) const { return _num_chunks_by_type[chunk_type]; }
Metachunk* get_new_chunk(size_t chunk_word_size);
@ -1619,7 +1614,7 @@ void VirtualSpaceNode::allocate_padding_chunks_until_top_is_at(MetaWord* target_
// Return Chunk to freelist.
inc_container_count();
chunk_manager->return_single_chunk(padding_chunk_type, padding_chunk);
chunk_manager->return_single_chunk(padding_chunk);
// Please note: at this point, ChunkManager::return_single_chunk()
// may already have merged the padding chunk with neighboring chunks, so
// it may have vanished at this point. Do not reference the padding
@ -2122,7 +2117,7 @@ void VirtualSpaceNode::retire(ChunkManager* chunk_manager) {
if (chunk == NULL) {
break;
}
chunk_manager->return_single_chunk(index, chunk);
chunk_manager->return_single_chunk(chunk);
}
DEBUG_ONLY(verify_container_count();)
}
@ -3026,10 +3021,10 @@ Metachunk* ChunkManager::chunk_freelist_allocate(size_t word_size) {
return chunk;
}
void ChunkManager::return_single_chunk(ChunkIndex index, Metachunk* chunk) {
void ChunkManager::return_single_chunk(Metachunk* chunk) {
const ChunkIndex index = chunk->get_chunk_type();
assert_lock_strong(MetaspaceExpand_lock);
DEBUG_ONLY(do_verify_chunk(chunk);)
assert(chunk->get_chunk_type() == index, "Chunk does not match expected index.");
assert(chunk != NULL, "Expected chunk.");
assert(chunk->container() != NULL, "Container should have been set.");
assert(chunk->is_tagged_free() == false, "Chunk should be in use.");
@ -3077,14 +3072,13 @@ void ChunkManager::return_single_chunk(ChunkIndex index, Metachunk* chunk) {
}
void ChunkManager::return_chunk_list(ChunkIndex index, Metachunk* chunks) {
index_bounds_check(index);
void ChunkManager::return_chunk_list(Metachunk* chunks) {
if (chunks == NULL) {
return;
}
LogTarget(Trace, gc, metaspace, freelist) log;
if (log.is_enabled()) { // tracing
log.print("returning list of %s chunks...", chunk_size_name(index));
log.print("returning list of chunks...");
}
unsigned num_chunks_returned = 0;
size_t size_chunks_returned = 0;
@ -3097,17 +3091,12 @@ void ChunkManager::return_chunk_list(ChunkIndex index, Metachunk* chunks) {
num_chunks_returned ++;
size_chunks_returned += cur->word_size();
}
return_single_chunk(index, cur);
return_single_chunk(cur);
cur = next;
}
if (log.is_enabled()) { // tracing
log.print("returned %u %s chunks to freelist, total word size " SIZE_FORMAT ".",
num_chunks_returned, chunk_size_name(index), size_chunks_returned);
if (index != HumongousIndex) {
log.print("updated freelist count: " SIZE_FORMAT ".", free_chunks(index)->size());
} else {
log.print("updated dictionary count " SIZE_FORMAT ".", _humongous_dictionary.total_count());
}
log.print("returned %u chunks to freelist, total word size " SIZE_FORMAT ".",
num_chunks_returned, size_chunks_returned);
}
}
@ -3170,28 +3159,11 @@ size_t SpaceManager::get_initial_chunk_size(Metaspace::MetaspaceType type) const
return adjusted;
}
size_t SpaceManager::sum_count_in_chunks_in_use(ChunkIndex i) {
size_t count = 0;
Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) {
count++;
chunk = chunk->next();
}
return count;
}
void SpaceManager::locked_print_chunks_in_use_on(outputStream* st) const {
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* chunk = chunks_in_use(i);
st->print("SpaceManager: %s " PTR_FORMAT,
chunk_size_name(i), p2i(chunk));
if (chunk != NULL) {
st->print_cr(" free " SIZE_FORMAT,
chunk->free_word_size());
} else {
st->cr();
}
st->print("SpaceManager: " UINTX_FORMAT " %s chunks.",
num_chunks_by_type(i), chunk_size_name(i));
}
chunk_manager()->locked_print_free_chunks(st);
@ -3212,13 +3184,13 @@ size_t SpaceManager::calc_chunk_size(size_t word_size) {
// reduces space waste from 60+% to around 30%.
if ((_space_type == Metaspace::AnonymousMetaspaceType || _space_type == Metaspace::ReflectionMetaspaceType) &&
_mdtype == Metaspace::NonClassType &&
sum_count_in_chunks_in_use(SpecializedIndex) < _anon_and_delegating_metadata_specialize_chunk_limit &&
num_chunks_by_type(SpecializedIndex) < _anon_and_delegating_metadata_specialize_chunk_limit &&
word_size + Metachunk::overhead() <= SpecializedChunk) {
return SpecializedChunk;
}
if (chunks_in_use(MediumIndex) == NULL &&
sum_count_in_chunks_in_use(SmallIndex) < _small_chunk_limit) {
if (num_chunks_by_type(MediumIndex) == 0 &&
num_chunks_by_type(SmallIndex) < _small_chunk_limit) {
chunk_word_size = (size_t) small_chunk_size();
if (word_size + Metachunk::overhead() > small_chunk_size()) {
chunk_word_size = medium_chunk_size();
@ -3324,9 +3296,13 @@ SpaceManager::SpaceManager(Metaspace::MetadataType mdtype,
_used_words(0),
_overhead_words(0),
_block_freelists(NULL),
_lock(lock)
_lock(lock),
_chunk_list(NULL),
_current_chunk(NULL)
{
initialize();
Metadebug::init_allocation_fail_alot_count();
memset(_num_chunks_by_type, 0, sizeof(_num_chunks_by_type));
log_trace(gc, metaspace, freelist)("SpaceManager(): " PTR_FORMAT, p2i(this));
}
void SpaceManager::account_for_new_chunk(const Metachunk* new_chunk) {
@ -3335,6 +3311,8 @@ void SpaceManager::account_for_new_chunk(const Metachunk* new_chunk) {
_capacity_words += new_chunk->word_size();
_overhead_words += Metachunk::overhead();
DEBUG_ONLY(new_chunk->verify());
_num_chunks_by_type[new_chunk->get_chunk_type()] ++;
// Adjust global counters:
MetaspaceUtils::inc_capacity(mdtype(), new_chunk->word_size());
@ -3362,15 +3340,6 @@ void SpaceManager::account_for_spacemanager_death() {
MetaspaceUtils::dec_used(mdtype(), _used_words);
}
void SpaceManager::initialize() {
Metadebug::init_allocation_fail_alot_count();
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
_chunks_in_use[i] = NULL;
}
_current_chunk = NULL;
log_trace(gc, metaspace, freelist)("SpaceManager(): " PTR_FORMAT, p2i(this));
}
SpaceManager::~SpaceManager() {
// This call this->_lock which can't be done while holding MetaspaceExpand_lock
@ -3399,12 +3368,11 @@ SpaceManager::~SpaceManager() {
// Follow each list of chunks-in-use and add them to the
// free lists. Each list is NULL terminated.
for (ChunkIndex i = ZeroIndex; i <= HumongousIndex; i = next_chunk_index(i)) {
Metachunk* chunks = chunks_in_use(i);
chunk_manager()->return_chunk_list(i, chunks);
set_chunks_in_use(i, NULL);
}
chunk_manager()->return_chunk_list(chunk_list());
#ifdef ASSERT
_chunk_list = NULL;
_current_chunk = NULL;
#endif
chunk_manager()->slow_locked_verify();
@ -3446,8 +3414,8 @@ void SpaceManager::add_chunk(Metachunk* new_chunk, bool make_current) {
}
// Add the new chunk at the head of its respective chunk list.
new_chunk->set_next(chunks_in_use(index));
set_chunks_in_use(index, new_chunk);
new_chunk->set_next(_chunk_list);
_chunk_list = new_chunk;
// Adjust counters.
account_for_new_chunk(new_chunk);
@ -3540,21 +3508,17 @@ MetaWord* SpaceManager::allocate_work(size_t word_size) {
if (result != NULL) {
account_for_allocation(word_size);
assert(result != (MetaWord*) chunks_in_use(MediumIndex),
"Head of the list is being allocated");
}
return result;
}
void SpaceManager::verify() {
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
Metachunk* curr = chunks_in_use(i);
while (curr != NULL) {
DEBUG_ONLY(do_verify_chunk(curr);)
assert(curr->is_tagged_free() == false, "Chunk should be tagged as in use.");
curr = curr->next();
}
Metachunk* curr = chunk_list();
while (curr != NULL) {
DEBUG_ONLY(do_verify_chunk(curr);)
assert(curr->is_tagged_free() == false, "Chunk should be tagged as in use.");
curr = curr->next();
}
}
@ -3569,21 +3533,19 @@ void SpaceManager::verify_chunk_size(Metachunk* chunk) {
void SpaceManager::add_to_statistics_locked(SpaceManagerStatistics* out) const {
assert_lock_strong(lock());
for (ChunkIndex i = ZeroIndex; i < NumberOfInUseLists; i = next_chunk_index(i)) {
UsedChunksStatistics& chunk_stat = out->chunk_stats(i);
Metachunk* chunk = chunks_in_use(i);
while (chunk != NULL) {
chunk_stat.add_num(1);
chunk_stat.add_cap(chunk->word_size());
chunk_stat.add_overhead(Metachunk::overhead());
chunk_stat.add_used(chunk->used_word_size() - Metachunk::overhead());
if (chunk != current_chunk()) {
chunk_stat.add_waste(chunk->free_word_size());
} else {
chunk_stat.add_free(chunk->free_word_size());
}
chunk = chunk->next();
Metachunk* chunk = chunk_list();
while (chunk != NULL) {
UsedChunksStatistics& chunk_stat = out->chunk_stats(chunk->get_chunk_type());
chunk_stat.add_num(1);
chunk_stat.add_cap(chunk->word_size());
chunk_stat.add_overhead(Metachunk::overhead());
chunk_stat.add_used(chunk->used_word_size() - Metachunk::overhead());
if (chunk != current_chunk()) {
chunk_stat.add_waste(chunk->free_word_size());
} else {
chunk_stat.add_free(chunk->free_word_size());
}
chunk = chunk->next();
}
if (block_freelists() != NULL) {
out->add_free_blocks_info(block_freelists()->num_blocks(), block_freelists()->total_size());