< prev index next >
src/hotspot/share/memory/metaspace/metachunk.hpp
Print this page
rev 57511 : [mq]: metaspace-improvement
@@ -22,152 +22,215 @@
*
*/
#ifndef SHARE_MEMORY_METASPACE_METACHUNK_HPP
#define SHARE_MEMORY_METASPACE_METACHUNK_HPP
-#include "memory/metaspace/metabase.hpp"
-#include "memory/metaspace/metaspaceCommon.hpp"
+
+#include "memory/metaspace/counter.hpp"
+#include "memory/metaspace/abstractPool.hpp"
+#include "memory/metaspace/chunkLevel.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 --+ --+
+// +--------------+ <- end ----+ --+
// | | | |
// | | | free |
+// | | |
+// | | | | size (aka capacity)
// | | | |
-// | | | | size | capacity
-// | | | |
-// | | <- top -- + |
+// | ----------- | <- 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;
+// +--------------+ <- start -- + -- +
- ChunkOrigin _origin;
- int _use_count;
+// 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;
+ }
- MetaWord* initial_top() const { return (MetaWord*)this + overhead(); }
- MetaWord* top() const { return _top; }
+ //// Debug stuff ////
+ DEBUG_ONLY(void verify(bool slow) const;)
- 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; }
+class MetachunkList {
- int get_use_count() const { return _use_count; }
- void inc_use_count() { _use_count ++; }
+ Metachunk* _first;
+ IntCounter _num;
- ChunkOrigin get_origin() const { return _origin; }
- void set_origin(ChunkOrigin orig) { _origin = orig; }
+public:
- ChunkIndex get_chunk_type() const { return _chunk_type; }
- bool is_class() const { return _is_class; }
+ MetachunkList() : _first(NULL), _num() {}
- DEBUG_ONLY(void mangle(juint word_value);)
- DEBUG_ONLY(void verify() const;)
+ 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
};
-
-// 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
< prev index next >