< 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 >