< prev index next >
src/hotspot/share/memory/metaspace/metachunk.hpp
Print this page
rev 57601 : [mq]: metaspace-improvement
*** 22,173 ****
*
*/
#ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
#define SHARE_MEMORY_METASPACE_METACHUNK_HPP
! #include "memory/metaspace/metabase.hpp"
! #include "memory/metaspace/metaspaceCommon.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
! class MetachunkTest;
namespace metaspace {
class VirtualSpaceNode;
// Metachunk - Quantum of allocation from a Virtualspace
// Metachunks are reused (when freed are put on a global freelist) and
// have no permanent association to a SpaceManager.
! // +--------------+ <- end --+ --+
// | | | |
// | | | free |
// | | | |
! // | | | | size | capacity
! // | | | |
! // | | <- top -- + |
// | | | |
// | | | used |
! // | | | |
! // | | | |
! // +--------------+ <- bottom --+ --+
!
! enum ChunkOrigin {
! // Chunk normally born (via take_from_committed)
! origin_normal = 1,
! // Chunk was born as padding chunk
! origin_pad = 2,
! // Chunk was born as leftover chunk in VirtualSpaceNode::retire
! origin_leftover = 3,
! // Chunk was born as result of a merge of smaller chunks
! origin_merge = 4,
! // Chunk was born as result of a split of a larger chunk
! origin_split = 5,
!
! origin_minimum = origin_normal,
! origin_maximum = origin_split,
! origins_count = origin_maximum + 1
! };
!
! inline bool is_valid_chunkorigin(ChunkOrigin origin) {
! return origin == origin_normal ||
! origin == origin_pad ||
! origin == origin_leftover ||
! origin == origin_merge ||
! origin == origin_split;
! }
!
! class Metachunk : public Metabase<Metachunk> {
!
! friend class ::MetachunkTest;
!
! // The VirtualSpaceNode containing this chunk.
! VirtualSpaceNode* const _container;
!
! // Current allocation top.
! MetaWord* _top;
!
! // A 32bit sentinel for debugging purposes.
! enum { CHUNK_SENTINEL = 0x4d4554EF, // "MET"
! CHUNK_SENTINEL_INVALID = 0xFEEEEEEF
! };
!
! uint32_t _sentinel;
!
! const ChunkIndex _chunk_type;
! const bool _is_class;
! // Whether the chunk is free (in freelist) or in use by some class loader.
! bool _is_tagged_free;
! ChunkOrigin _origin;
! int _use_count;
! MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
! MetaWord* top() const { return _top; }
! public:
! // Metachunks are allocated out of a MetadataVirtualSpace and
! // and use some of its space to describe itself (plus alignment
! // considerations). Metadata is allocated in the rest of the chunk.
! // This size is the overhead of maintaining the Metachunk within
! // the space.
!
! // Alignment of each allocation in the chunks.
! static size_t object_alignment();
!
! // Size of the Metachunk header, in words, including alignment.
! static size_t overhead();
!
! Metachunk(ChunkIndex chunktype, bool is_class, size_t word_size, VirtualSpaceNode* container);
!
! MetaWord* allocate(size_t word_size);
!
! VirtualSpaceNode* container() const { return _container; }
!
! MetaWord* bottom() const { return (MetaWord*) this; }
!
! // Reset top to bottom so chunk can be reused.
! void reset_empty() { _top = initial_top(); clear_next(); clear_prev(); }
! bool is_empty() { return _top == initial_top(); }
!
! // used (has been allocated)
! // free (available for future allocations)
! size_t word_size() const { return size(); }
! size_t used_word_size() const;
! size_t free_word_size() const;
!
! bool is_tagged_free() { return _is_tagged_free; }
! void set_is_tagged_free(bool v) { _is_tagged_free = v; }
!
! bool contains(const void* ptr) { return bottom() <= ptr && ptr < _top; }
- void print_on(outputStream* st) const;
! bool is_valid_sentinel() const { return _sentinel == CHUNK_SENTINEL; }
! void remove_sentinel() { _sentinel = CHUNK_SENTINEL_INVALID; }
! int get_use_count() const { return _use_count; }
! void inc_use_count() { _use_count ++; }
! ChunkOrigin get_origin() const { return _origin; }
! void set_origin(ChunkOrigin orig) { _origin = orig; }
! ChunkIndex get_chunk_type() const { return _chunk_type; }
! bool is_class() const { return _is_class; }
! DEBUG_ONLY(void mangle(juint word_value);)
! DEBUG_ONLY(void verify() const;)
};
-
- // Helper function that does a bunch of checks for a chunk.
- DEBUG_ONLY(void do_verify_chunk(Metachunk* chunk);)
-
- // Given a Metachunk, update its in-use information (both in the
- // chunk and the occupancy map).
- void do_update_in_use_info_for_chunk(Metachunk* chunk, bool inuse);
-
} // namespace metaspace
#endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
--- 22,236 ----
*
*/
#ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
#define SHARE_MEMORY_METASPACE_METACHUNK_HPP
!
! #include "memory/metaspace/counter.hpp"
! #include "memory/metaspace/abstractPool.hpp"
! #include "memory/metaspace/chunkLevel.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
!
namespace metaspace {
class VirtualSpaceNode;
// Metachunk - Quantum of allocation from a Virtualspace
// Metachunks are reused (when freed are put on a global freelist) and
// have no permanent association to a SpaceManager.
! // +--------------+ <- end ----+ --+
// | | | |
// | | | free |
+ // | | |
+ // | | | | size (aka capacity)
// | | | |
! // | ----------- | <- top -- + |
// | | | |
// | | | used |
! // +--------------+ <- start -- + -- +
! // Note: this is a chunk **descriptor**. The real Payload area lives in metaspace,
! // this class lives somewhere else.
! class Metachunk {
!
! // Todo: compact this node. A lot of things can be expressed more tighter.
!
! // A chunk header is kept in a list:
! // - in the list of used chunks inside a SpaceManager, if it is in use
! // - in the list of free chunks inside a ChunkManager, if it is free
! // - in the freelist of dead headers inside the MetaChunkHeaderPool,
! // if it is dead (e.g. result of chunk merging).
! Metachunk* _prev;
! Metachunk* _next;
!
! chklvl_t _level; // aka size.
!
! // true: free, owned by ChunkManager
! // false: in-use, owned by SpaceManager
! // if dead, meaningless
! bool _is_free;
!
! // start of chunk memory; NULL if dead.
! MetaWord* _base;
!
! // Used words.
! size_t _used_words;
!
! // Guaranteed-to-be-committed-words, counted from base
! // (This is a performance optimization. The underlying VirtualSpaceNode knows
! // which granules are committed; but we want to avoid asking it unnecessarily
! // in Metachunk::allocate(), so we keep a limit until which we are guaranteed
! // to have committed memory under us.)
! size_t _committed_words;
!
! // the chunk tree node this header is hanging under; NULL if dead.
! u2 _tree_node_ref;
!
! // We need unfortunately a back link to the virtual space node
! // for splitting and merging nodes.
! VirtualSpaceNode* _vsnode;
!
! MetaWord* top() const { return base() + _used_words; }
!
! public:
!
! Metachunk()
! : _prev(NULL), _next(NULL),
! _level(chklvl::ROOT_CHUNK_LEVEL),
! _is_free(true),
! _base(NULL),
! _used_words(0),
! _committed_words(0),
! _tree_node_ref(0),
! _vsnode(NULL)
! {}
!
! size_t word_size() const { return chklvl::word_size_for_level(_level); }
!
! MetaWord* base() const { return _base; }
! void set_base(MetaWord* p) { _base = p; }
! MetaWord* end() const { return base() + word_size(); }
!
! void set_prev(Metachunk* c) { _prev = c; }
! Metachunk* prev() const { return _prev; }
! void set_next(Metachunk* c) { _next = c; }
! Metachunk* next() const { return _next; }
! // Remove chunk from whatever list it lives in by wiring next with previous.
! void remove_from_list();
!
! bool is_free() const { return _is_free; }
! bool is_in_use() const { return !_is_free; }
! void set_free(bool v) { _is_free = v; }
!
!
! void inc_level() { _level ++; DEBUG_ONLY(chklvl::is_valid_level(_level);) }
! void dec_level() { _level --; DEBUG_ONLY(chklvl::is_valid_level(_level);) }
! void set_level(chklvl_t v) { _level = v; DEBUG_ONLY(chklvl::is_valid_level(_level);) }
! chklvl_t level() const { return _level; }
!
! void set_tree_node_ref(u2 v) { _tree_node_ref = v; }
! u2 tree_node_ref() const { return _tree_node_ref; }
!
! VirtualSpaceNode* vsnode() const { return _vsnode; }
! void set_vsnode(VirtualSpaceNode* n) { _vsnode = n; }
!
! size_t used_words() const { return _used_words; }
! size_t free_words() const { return word_size() - used_words(); }
! size_t free_below_committed_words() const { return committed_words() - used_words(); }
! void reset_used_words() { _used_words = 0; }
!
! size_t committed_words() const { return _committed_words; }
! void set_committed_words(size_t v) { _committed_words = v; }
! bool is_fully_committed() const { return committed_words() == word_size(); }
!
! // Ensure that chunk is committed up to at least word_size words.
! // Fails if we hit a commit limit.
! bool ensure_committed(size_t word_size);
!
! // Alignment of an allocation.
! static const size_t allocation_alignment_bytes = 8;
! static const size_t allocation_alignment_words = allocation_alignment_bytes / BytesPerWord;
!
! // Allocation from a chunk
!
! // Allocate word_size words from this chunk.
! //
! // May cause memory to be committed. That may fail if we hit a commit limit. In that case,
! // NULL is returned and p_did_hit_commit_limit will be set to true.
! // If the remainder portion of the chunk was too small to hold the allocation,
! // NULL is returned and p_did_hit_commit_limit will be set to false.
! MetaWord* allocate(size_t word_size, bool* p_did_hit_commit_limit);
!
! // Wipe this object to look as if it were default constructed.
! void wipe() {
! _prev = NULL; _next = NULL;
! _level = chklvl::ROOT_CHUNK_LEVEL;
! _is_free = true;
! _base = NULL;
! _used_words = 0;
! _committed_words = 0;
! _tree_node_ref = 0;
! _vsnode = NULL;
! }
! //// Debug stuff ////
! DEBUG_ONLY(void verify(bool slow) const;)
! };
! class MetachunkList {
! Metachunk* _first;
! IntCounter _num;
! public:
! MetachunkList() : _first(NULL), _num() {}
! Metachunk* first() const { return _first; }
! int size() const { return _num.get(); }
!
! void add(Metachunk* c) {
! c->set_next(_first);
! _first = c;
! _num.increment();
! }
!
! // Remove first node unless empty. Returns node or NULL.
! Metachunk* remove_first() {
! Metachunk* c = _first;
! if (c != NULL) {
! _first = c->next();
! _num.decrement();
! }
! return c;
! }
!
! // Remove given chunk from list. List must contain that chunk.
! void remove(Metachunk* c) {
! assert(contains(c), "Does not contain this chunk");
! c->remove_from_list();
! _num.decrement();
! }
!
! // Manually decrement counter; needed for cases where chunks
! // have been manually removed from the list without informing
! // the list, e.g. chunk merging, see chunkManager::return_chunk().
! void dec_counter_by(int v) {
! _num.decrement_by(v);
! }
!
! #ifdef ASSERT
! bool contains(const Metachunk* c) const;
! void verify(bool slow) const;
! #endif
};
} // namespace metaspace
#endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
< prev index next >