blob: 75d1ec5318c346c9a704469715f81a8bdda44dc1 [file] [edit]
/*
* Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2020 SAP SE. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_MEMORY_METASPACE_METASPACEARENA_HPP
#define SHARE_MEMORY_METASPACE_METASPACEARENA_HPP
#include "memory/allocation.hpp"
#include "memory/metaspace.hpp"
#include "memory/metaspace/counters.hpp"
#include "memory/metaspace/metablock.hpp"
#include "memory/metaspace/metachunkList.hpp"
class outputStream;
class Mutex;
namespace metaspace {
class ArenaGrowthPolicy;
struct ArenaStats;
class ChunkManager;
class FreeBlocks;
class Metachunk;
class MetaspaceContext;
// The MetaspaceArena is a growable metaspace memory pool belonging to a CLD;
// internally it consists of a list of metaspace chunks, of which the head chunk
// is the current chunk from which we allocate via pointer bump.
//
// +---------------+
// | Arena |
// +---------------+
// |
// | _chunks commit top
// | v
// +----------+ +----------+ +----------+ +----------+
// | retired | ---> | retired | ---> | retired | ---> | current |
// | chunk | | chunk | | chunk | | chunk |
// +----------+ +----------+ +----------+ +----------+
// ^
// used top
//
// +------------+
// | FreeBlocks | --> O -> O -> O -> O
// +------------+
//
//
// When the current chunk is used up, MetaspaceArena requests a new chunk from
// the associated ChunkManager.
//
// MetaspaceArena also keeps a FreeBlocks structure to manage memory blocks which
// had been deallocated prematurely.
//
class MetaspaceArena : public CHeapObj<mtClass> {
friend class MetaspaceArenaTestFriend;
// Please note that access to a metaspace arena may be shared
// between threads and needs to be synchronized in CLMS.
// Allocation alignment specific to this arena
const size_t _allocation_alignment_words;
// Reference to the chunk manager to allocate chunks from.
ChunkManager* const _chunk_manager;
// Reference to the growth policy to use.
const ArenaGrowthPolicy* const _growth_policy;
// List of chunks. Head of the list is the current chunk.
MetachunkList _chunks;
// Structure to take care of leftover/deallocated space in used chunks.
// Owned by the Arena. Gets allocated on demand only.
FreeBlocks* _fbl;
Metachunk* current_chunk() { return _chunks.first(); }
const Metachunk* current_chunk() const { return _chunks.first(); }
// Reference to an outside counter to keep track of used space.
SizeAtomicCounter* const _total_used_words_counter;
// A name for purely debugging/logging purposes.
const char* const _name;
ChunkManager* chunk_manager() const { return _chunk_manager; }
// free block list
FreeBlocks* fbl() const { return _fbl; }
void add_allocation_to_fbl(MetaBlock bl);
// Given a chunk, return the committed remainder of this chunk.
MetaBlock salvage_chunk(Metachunk* c);
// Allocate a new chunk from the underlying chunk manager able to hold at least
// requested word size.
Metachunk* allocate_new_chunk(size_t requested_word_size);
// Returns the level of the next chunk to be added, acc to growth policy.
chunklevel_t next_chunk_level() const;
// Attempt to enlarge the current chunk to make it large enough to hold at least
// requested_word_size additional words.
//
// On success, true is returned, false otherwise.
bool attempt_enlarge_current_chunk(size_t requested_word_size);
// Allocate from the arena proper, once dictionary allocations and fencing are sorted out.
MetaBlock allocate_inner(size_t word_size, MetaBlock& wastage);
public:
MetaspaceArena(MetaspaceContext* context,
const ArenaGrowthPolicy* growth_policy,
size_t allocation_alignment_words,
const char* name);
~MetaspaceArena();
size_t allocation_alignment_words() const { return _allocation_alignment_words; }
size_t allocation_alignment_bytes() const { return allocation_alignment_words() * BytesPerWord; }
// Allocate memory from Metaspace.
// On success, returns non-empty block of the specified word size, and
// possibly a wastage block that is the result of alignment operations.
// On failure, returns an empty block. Failure may happen if we hit a
// commit limit.
MetaBlock allocate(size_t word_size, MetaBlock& wastage);
// Prematurely returns a metaspace allocation to the _block_freelists because it is not
// needed anymore.
void deallocate(MetaBlock bl);
// Update statistics. This walks all in-use chunks.
void add_to_statistics(ArenaStats* out) const;
// Convenience method to get the most important usage statistics.
// For deeper analysis use add_to_statistics().
void usage_numbers(size_t* p_used_words, size_t* p_committed_words, size_t* p_capacity_words) const;
DEBUG_ONLY(void verify() const;)
DEBUG_ONLY(void verify_allocation_guards() const;)
void print_on(outputStream* st) const;
// Returns true if the given block is contained in this arena
DEBUG_ONLY(bool contains(MetaBlock bl) const;)
};
} // namespace metaspace
#endif // SHARE_MEMORY_METASPACE_METASPACEARENA_HPP