Path: blob/master/src/hotspot/share/memory/metaspace/metaspaceArena.cpp
40957 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#include "precompiled.hpp"26#include "logging/log.hpp"27#include "logging/logStream.hpp"28#include "memory/metaspace/allocationGuard.hpp"29#include "memory/metaspace/chunkManager.hpp"30#include "memory/metaspace/counters.hpp"31#include "memory/metaspace/freeBlocks.hpp"32#include "memory/metaspace/internalStats.hpp"33#include "memory/metaspace/metachunk.hpp"34#include "memory/metaspace/metaspaceArena.hpp"35#include "memory/metaspace/metaspaceArenaGrowthPolicy.hpp"36#include "memory/metaspace/metaspaceCommon.hpp"37#include "memory/metaspace/metaspaceSettings.hpp"38#include "memory/metaspace/metaspaceStatistics.hpp"39#include "memory/metaspace/virtualSpaceList.hpp"40#include "runtime/atomic.hpp"41#include "runtime/init.hpp"42#include "runtime/mutexLocker.hpp"43#include "services/memoryService.hpp"44#include "utilities/align.hpp"45#include "utilities/debug.hpp"46#include "utilities/globalDefinitions.hpp"4748namespace metaspace {4950#define LOGFMT "Arena @" PTR_FORMAT " (%s)"51#define LOGFMT_ARGS p2i(this), this->_name5253// Returns the level of the next chunk to be added, acc to growth policy.54chunklevel_t MetaspaceArena::next_chunk_level() const {55const int growth_step = _chunks.count();56return _growth_policy->get_level_at_step(growth_step);57}5859// Given a chunk, add its remaining free committed space to the free block list.60void MetaspaceArena::salvage_chunk(Metachunk* c) {61if (Settings::handle_deallocations() == false) {62return;63}6465assert_lock_strong(lock());66size_t remaining_words = c->free_below_committed_words();67if (remaining_words > FreeBlocks::MinWordSize) {6869UL2(trace, "salvaging chunk " METACHUNK_FULL_FORMAT ".", METACHUNK_FULL_FORMAT_ARGS(c));7071MetaWord* ptr = c->allocate(remaining_words);72assert(ptr != NULL, "Should have worked");73_total_used_words_counter->increment_by(remaining_words);7475add_allocation_to_fbl(ptr, remaining_words);7677// After this operation: the chunk should have no free committed space left.78assert(c->free_below_committed_words() == 0,79"Salvaging chunk failed (chunk " METACHUNK_FULL_FORMAT ").",80METACHUNK_FULL_FORMAT_ARGS(c));81}82}8384// Allocate a new chunk from the underlying chunk manager able to hold at least85// requested word size.86Metachunk* MetaspaceArena::allocate_new_chunk(size_t requested_word_size) {87assert_lock_strong(lock());8889// Should this ever happen, we need to increase the maximum possible chunk size.90guarantee(requested_word_size <= chunklevel::MAX_CHUNK_WORD_SIZE,91"Requested size too large (" SIZE_FORMAT ") - max allowed size per allocation is " SIZE_FORMAT ".",92requested_word_size, chunklevel::MAX_CHUNK_WORD_SIZE);9394const chunklevel_t max_level = chunklevel::level_fitting_word_size(requested_word_size);95const chunklevel_t preferred_level = MIN2(max_level, next_chunk_level());9697Metachunk* c = _chunk_manager->get_chunk(preferred_level, max_level, requested_word_size);98if (c == NULL) {99return NULL;100}101102assert(c->is_in_use(), "Wrong chunk state.");103assert(c->free_below_committed_words() >= requested_word_size, "Chunk not committed");104return c;105}106107void MetaspaceArena::add_allocation_to_fbl(MetaWord* p, size_t word_size) {108assert(Settings::handle_deallocations(), "Sanity");109if (_fbl == NULL) {110_fbl = new FreeBlocks(); // Create only on demand111}112_fbl->add_block(p, word_size);113}114115MetaspaceArena::MetaspaceArena(ChunkManager* chunk_manager, const ArenaGrowthPolicy* growth_policy,116Mutex* lock, SizeAtomicCounter* total_used_words_counter,117const char* name) :118_lock(lock),119_chunk_manager(chunk_manager),120_growth_policy(growth_policy),121_chunks(),122_fbl(NULL),123_total_used_words_counter(total_used_words_counter),124_name(name)125{126UL(debug, ": born.");127128// Update statistics129InternalStats::inc_num_arena_births();130}131132MetaspaceArena::~MetaspaceArena() {133#ifdef ASSERT134verify();135if (Settings::use_allocation_guard()) {136verify_allocation_guards();137}138#endif139140MutexLocker fcl(lock(), Mutex::_no_safepoint_check_flag);141MemRangeCounter return_counter;142143Metachunk* c = _chunks.first();144Metachunk* c2 = NULL;145146while (c) {147c2 = c->next();148return_counter.add(c->used_words());149DEBUG_ONLY(c->set_prev(NULL);)150DEBUG_ONLY(c->set_next(NULL);)151UL2(debug, "return chunk: " METACHUNK_FORMAT ".", METACHUNK_FORMAT_ARGS(c));152_chunk_manager->return_chunk(c);153// c may be invalid after return_chunk(c) was called. Don't access anymore.154c = c2;155}156157UL2(info, "returned %d chunks, total capacity " SIZE_FORMAT " words.",158return_counter.count(), return_counter.total_size());159160_total_used_words_counter->decrement_by(return_counter.total_size());161DEBUG_ONLY(chunk_manager()->verify();)162delete _fbl;163UL(debug, ": dies.");164165// Update statistics166InternalStats::inc_num_arena_deaths();167}168169// Attempt to enlarge the current chunk to make it large enough to hold at least170// requested_word_size additional words.171//172// On success, true is returned, false otherwise.173bool MetaspaceArena::attempt_enlarge_current_chunk(size_t requested_word_size) {174assert_lock_strong(lock());175176Metachunk* c = current_chunk();177assert(c->free_words() < requested_word_size, "Sanity");178179// Not if chunk enlargment is switched off...180if (Settings::enlarge_chunks_in_place() == false) {181return false;182}183// ... nor if we are already a root chunk ...184if (c->is_root_chunk()) {185return false;186}187// ... nor if the combined size of chunk content and new content would bring us above the size of a root chunk ...188if ((c->used_words() + requested_word_size) > metaspace::chunklevel::MAX_CHUNK_WORD_SIZE) {189return false;190}191192const chunklevel_t new_level =193chunklevel::level_fitting_word_size(c->used_words() + requested_word_size);194assert(new_level < c->level(), "Sanity");195196// Atm we only enlarge by one level (so, doubling the chunk in size). So, if the requested enlargement197// would require the chunk to more than double in size, we bail. But this covers about 99% of all cases,198// so this is good enough.199if (new_level < c->level() - 1) {200return false;201}202// This only works if chunk is the leader of its buddy pair (and also if buddy203// is free and unsplit, but that we cannot check outside of metaspace lock).204if (!c->is_leader()) {205return false;206}207// If the size added to the chunk would be larger than allowed for the next growth step208// dont enlarge.209if (next_chunk_level() > c->level()) {210return false;211}212213bool success = _chunk_manager->attempt_enlarge_chunk(c);214assert(success == false || c->free_words() >= requested_word_size, "Sanity");215return success;216}217218// Allocate memory from Metaspace.219// 1) Attempt to allocate from the free block list.220// 2) Attempt to allocate from the current chunk.221// 3) Attempt to enlarge the current chunk in place if it is too small.222// 4) Attempt to get a new chunk and allocate from that chunk.223// At any point, if we hit a commit limit, we return NULL.224MetaWord* MetaspaceArena::allocate(size_t requested_word_size) {225MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);226UL2(trace, "requested " SIZE_FORMAT " words.", requested_word_size);227228MetaWord* p = NULL;229const size_t raw_word_size = get_raw_word_size_for_requested_word_size(requested_word_size);230231// 1) Attempt to allocate from the free blocks list232// (Note: to reduce complexity, deallocation handling is disabled if allocation guards233// are enabled, see Settings::ergo_initialize())234if (Settings::handle_deallocations() && _fbl != NULL && !_fbl->is_empty()) {235p = _fbl->remove_block(raw_word_size);236if (p != NULL) {237DEBUG_ONLY(InternalStats::inc_num_allocs_from_deallocated_blocks();)238UL2(trace, "taken from fbl (now: %d, " SIZE_FORMAT ").",239_fbl->count(), _fbl->total_size());240// Note: Space which is kept in the freeblock dictionary still counts as used as far241// as statistics go; therefore we skip the epilogue in this function to avoid double242// accounting.243return p;244}245}246247bool current_chunk_too_small = false;248bool commit_failure = false;249250if (current_chunk() != NULL) {251252// 2) Attempt to satisfy the allocation from the current chunk.253254// If the current chunk is too small to hold the requested size, attempt to enlarge it.255// If that fails, retire the chunk.256if (current_chunk()->free_words() < raw_word_size) {257if (!attempt_enlarge_current_chunk(raw_word_size)) {258current_chunk_too_small = true;259} else {260DEBUG_ONLY(InternalStats::inc_num_chunks_enlarged();)261UL(debug, "enlarged chunk.");262}263}264265// Commit the chunk far enough to hold the requested word size. If that fails, we266// hit a limit (either GC threshold or MaxMetaspaceSize). In that case retire the267// chunk.268if (!current_chunk_too_small) {269if (!current_chunk()->ensure_committed_additional(raw_word_size)) {270UL2(info, "commit failure (requested size: " SIZE_FORMAT ")", raw_word_size);271commit_failure = true;272}273}274275// Allocate from the current chunk. This should work now.276if (!current_chunk_too_small && !commit_failure) {277p = current_chunk()->allocate(raw_word_size);278assert(p != NULL, "Allocation from chunk failed.");279}280}281282if (p == NULL) {283// If we are here, we either had no current chunk to begin with or it was deemed insufficient.284assert(current_chunk() == NULL ||285current_chunk_too_small || commit_failure, "Sanity");286287Metachunk* new_chunk = allocate_new_chunk(raw_word_size);288if (new_chunk != NULL) {289UL2(debug, "allocated new chunk " METACHUNK_FORMAT " for requested word size " SIZE_FORMAT ".",290METACHUNK_FORMAT_ARGS(new_chunk), requested_word_size);291292assert(new_chunk->free_below_committed_words() >= raw_word_size, "Sanity");293if (Settings::new_chunks_are_fully_committed()) {294assert(new_chunk->is_fully_committed(), "Chunk should be fully committed.");295}296297// We have a new chunk. Before making it the current chunk, retire the old one.298if (current_chunk() != NULL) {299salvage_chunk(current_chunk());300DEBUG_ONLY(InternalStats::inc_num_chunks_retired();)301}302303_chunks.add(new_chunk);304305// Now, allocate from that chunk. That should work.306p = current_chunk()->allocate(raw_word_size);307assert(p != NULL, "Allocation from chunk failed.");308} else {309UL2(info, "failed to allocate new chunk for requested word size " SIZE_FORMAT ".", requested_word_size);310}311}312313#ifdef ASSERT314// When using allocation guards, establish a prefix.315if (p != NULL && Settings::use_allocation_guard()) {316p = establish_prefix(p, raw_word_size);317}318#endif319320if (p == NULL) {321InternalStats::inc_num_allocs_failed_limit();322} else {323DEBUG_ONLY(InternalStats::inc_num_allocs();)324_total_used_words_counter->increment_by(raw_word_size);325}326327SOMETIMES(verify_locked();)328329if (p == NULL) {330UL(info, "allocation failed, returned NULL.");331} else {332UL2(trace, "after allocation: %u chunk(s), current:" METACHUNK_FULL_FORMAT,333_chunks.count(), METACHUNK_FULL_FORMAT_ARGS(current_chunk()));334UL2(trace, "returning " PTR_FORMAT ".", p2i(p));335}336return p;337}338339// Prematurely returns a metaspace allocation to the _block_freelists340// because it is not needed anymore (requires CLD lock to be active).341void MetaspaceArena::deallocate_locked(MetaWord* p, size_t word_size) {342if (Settings::handle_deallocations() == false) {343return;344}345346assert_lock_strong(lock());347// At this point a current chunk must exist since we only deallocate if we did allocate before.348assert(current_chunk() != NULL, "stray deallocation?");349assert(is_valid_area(p, word_size),350"Pointer range not part of this Arena and cannot be deallocated: (" PTR_FORMAT ".." PTR_FORMAT ").",351p2i(p), p2i(p + word_size));352353UL2(trace, "deallocating " PTR_FORMAT ", word size: " SIZE_FORMAT ".",354p2i(p), word_size);355356size_t raw_word_size = get_raw_word_size_for_requested_word_size(word_size);357add_allocation_to_fbl(p, raw_word_size);358359DEBUG_ONLY(verify_locked();)360}361362// Prematurely returns a metaspace allocation to the _block_freelists because it is not363// needed anymore.364void MetaspaceArena::deallocate(MetaWord* p, size_t word_size) {365MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);366deallocate_locked(p, word_size);367}368369// Update statistics. This walks all in-use chunks.370void MetaspaceArena::add_to_statistics(ArenaStats* out) const {371MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);372373for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {374InUseChunkStats& ucs = out->_stats[c->level()];375ucs._num++;376ucs._word_size += c->word_size();377ucs._committed_words += c->committed_words();378ucs._used_words += c->used_words();379// Note: for free and waste, we only count what's committed.380if (c == current_chunk()) {381ucs._free_words += c->free_below_committed_words();382} else {383ucs._waste_words += c->free_below_committed_words();384}385}386387if (_fbl != NULL) {388out->_free_blocks_num += _fbl->count();389out->_free_blocks_word_size += _fbl->total_size();390}391392SOMETIMES(out->verify();)393}394395// Convenience method to get the most important usage statistics.396// For deeper analysis use add_to_statistics().397void MetaspaceArena::usage_numbers(size_t* p_used_words, size_t* p_committed_words, size_t* p_capacity_words) const {398MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);399size_t used = 0, comm = 0, cap = 0;400for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {401used += c->used_words();402comm += c->committed_words();403cap += c->word_size();404}405if (p_used_words != NULL) {406*p_used_words = used;407}408if (p_committed_words != NULL) {409*p_committed_words = comm;410}411if (p_capacity_words != NULL) {412*p_capacity_words = cap;413}414}415416#ifdef ASSERT417418void MetaspaceArena::verify_locked() const {419assert_lock_strong(lock());420assert(_growth_policy != NULL && _chunk_manager != NULL, "Sanity");421_chunks.verify();422if (_fbl != NULL) {423_fbl->verify();424}425}426427void MetaspaceArena::verify_allocation_guards() const {428assert(Settings::use_allocation_guard(), "Don't call with guards disabled.");429430// Verify canaries of all allocations.431// (We can walk all allocations since at the start of a chunk an allocation432// must be present, and the allocation header contains its size, so we can433// find the next one).434for (const Metachunk* c = _chunks.first(); c != NULL; c = c->next()) {435const Prefix* first_broken_block = NULL;436int num_broken_blocks = 0;437const MetaWord* p = c->base();438while (p < c->top()) {439const Prefix* pp = (const Prefix*)p;440if (!pp->is_valid()) {441UL2(error, "Corrupt block at " PTR_FORMAT " (chunk: " METACHUNK_FORMAT ").",442p2i(pp), METACHUNK_FORMAT_ARGS(c));443if (first_broken_block == NULL) {444first_broken_block = pp;445}446num_broken_blocks ++;447}448p += pp->_word_size;449}450// After examining all blocks in a chunk, assert if any of those blocks451// was found to be corrupted.452if (first_broken_block != NULL) {453assert(false, "Corrupt block: found at least %d corrupt metaspace block(s) - "454"first corrupted block at " PTR_FORMAT ".",455num_broken_blocks, p2i(first_broken_block));456}457}458}459460void MetaspaceArena::verify() const {461MutexLocker cl(lock(), Mutex::_no_safepoint_check_flag);462verify_locked();463}464465// Returns true if the area indicated by pointer and size have actually been allocated466// from this arena.467bool MetaspaceArena::is_valid_area(MetaWord* p, size_t word_size) const {468assert(p != NULL && word_size > 0, "Sanity");469bool found = false;470for (const Metachunk* c = _chunks.first(); c != NULL && !found; c = c->next()) {471assert(c->is_valid_committed_pointer(p) ==472c->is_valid_committed_pointer(p + word_size - 1), "range intersects");473found = c->is_valid_committed_pointer(p);474}475return found;476}477478#endif // ASSERT479480void MetaspaceArena::print_on(outputStream* st) const {481MutexLocker fcl(_lock, Mutex::_no_safepoint_check_flag);482print_on_locked(st);483}484485void MetaspaceArena::print_on_locked(outputStream* st) const {486assert_lock_strong(_lock);487st->print_cr("sm %s: %d chunks, total word size: " SIZE_FORMAT ", committed word size: " SIZE_FORMAT, _name,488_chunks.count(), _chunks.calc_word_size(), _chunks.calc_committed_word_size());489_chunks.print_on(st);490st->cr();491st->print_cr("growth-policy " PTR_FORMAT ", lock " PTR_FORMAT ", cm " PTR_FORMAT ", fbl " PTR_FORMAT,492p2i(_growth_policy), p2i(_lock), p2i(_chunk_manager), p2i(_fbl));493}494495} // namespace metaspace496497498499