< prev index next >
src/hotspot/share/memory/metaspace/metachunk.hpp
Print this page
rev 57380 : [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,185 ----
*
*/
#ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
#define SHARE_MEMORY_METASPACE_METACHUNK_HPP
!
! #include "memory/metaspace/abstractPool.hpp"
! #include "memory/metaspace/chunkLevel.hpp"
#include "utilities/debug.hpp"
#include "utilities/globalDefinitions.hpp"
!
namespace metaspace {
+ struct qtnode_t;
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 {
!
! // 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;
!
! // the chunk tree node this header is hanging under; NULL if dead.
! qtnode_t* _tree_node;
!
! // 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; }
!
! Metachunk()
! : _prev(NULL), _next(NULL),
! _level(chklvl::ROOT_CHUNK_LEVEL),
! _is_free(true),
! _base(NULL),
! _used_words(0),
! _tree_node(NULL),
! _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(qtnode_t* n) { _tree_node = n; }
! qtnode_t* tree_node() const { return _tree_node; }
!
! 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(); }
! void reset_used_words() { _used_words = 0; }
!
! // 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);
! _tree_node(NULL);
! _vsnode(NULL);
! }
! //// Debug stuff ////
! DEBUG_ONLY(void verify(bool slow) const;)
! };
! class MetachunkPool : private AbstractPool<Metachunk, uint32_t> {
! public:
! static bool is_metachunk_pointer(void* p) {
! return is_valid_elem((Metachunk*)p);
! }
!
! // Allocate new Metachunk header. Header will be default constructed.
! static Metachunk* alloc_header() {
! Metachunk* c = allocate_element();
! c->wipe();
! return c;
! }
!
! // Mark a header as dead and return to the pool for later reuse.
! static void release_header(Metachunk* c) {
! DEBUG_ONLY(c->set_base(NULL);)
! return_element(c);
! }
};
} // namespace metaspace
#endif // SHARE_MEMORY_METASPACE_METACHUNK_HPP
< prev index next >