--- old/src/hotspot/share/memory/metaspace/spaceManager.hpp 2019-07-25 15:29:51.113259060 +0200 +++ new/src/hotspot/share/memory/metaspace/spaceManager.hpp 2019-07-25 15:29:50.889255884 +0200 @@ -28,206 +28,98 @@ #include "memory/allocation.hpp" #include "memory/metaspace.hpp" #include "memory/metaspace/blockFreelist.hpp" -#include "memory/metaspace/metaspaceCommon.hpp" +#include "memory/metaspace/chunkAllocSequence.hpp" +#include "memory/metaspace/chunkManager.hpp" #include "memory/metaspace/metachunk.hpp" -#include "memory/metaspace/metaspaceStatistics.hpp" -#include "utilities/debug.hpp" -#include "utilities/globalDefinitions.hpp" +#include "memory/metaspace/metaspaceCommon.hpp" class outputStream; class Mutex; namespace metaspace { -// SpaceManager - used by Metaspace to handle allocations -class SpaceManager : public CHeapObj { - friend class ::ClassLoaderMetaspace; - friend class Metadebug; +class SpaceManagerStatistics; - private: +// The SpaceManager: +// - keeps a list of chunks-in-use by the class loader, as well as a current chunk used +// to allocate from +// - keeps a dictionary of free MetaBlocks. Those can be remnants of a retired chunk or +// allocations which were not needed anymore for some reason (e.g. releasing half-allocated +// structures when class loading fails) - // protects allocations +class SpaceManager : public CHeapObj { + + // Lock handed down from the associated ClassLoaderData. + // Protects allocations from this space. Mutex* const _lock; - // Type of metadata allocated. - const Metaspace::MetadataType _mdtype; + // The chunk manager to allocate chunks from. + ChunkManager* const _chunk_manager; - // Type of metaspace - const Metaspace::MetaspaceType _space_type; + // The chunk allocation strategy to use. + const ChunkAllocSequence* const _chunk_alloc_sequence; // List of chunks in use by this SpaceManager. Allocations // are done from the current chunk. The list is used for deallocating // chunks when the SpaceManager is freed. - Metachunk* _chunk_list; + MetachunkList _chunks; Metachunk* _current_chunk; - enum { - - // Maximum number of small chunks to allocate to a SpaceManager - small_chunk_limit = 4, + // Prematurely released metablocks. + BlockFreelist* _block_freelist; - // Maximum number of specialize chunks to allocate for anonymous and delegating - // metadata space to a SpaceManager - anon_and_delegating_metadata_specialize_chunk_limit = 4, - allocation_from_dictionary_limit = 4 * K + // Statistics - }; - - // Some running counters, but lets keep their number small to not add to much to - // the per-classloader footprint. + // Running counters. // Note: capacity = used + free + waste + overhead. We do not keep running counters for // free and waste. Their sum can be deduced from the three other values. - size_t _overhead_words; - size_t _capacity_words; - size_t _used_words; - uintx _num_chunks_by_type[NumberOfInUseLists]; - - // Free lists of blocks are per SpaceManager since they - // are assumed to be in chunks in use by the SpaceManager - // and all chunks in use by a SpaceManager are freed when - // the class loader using the SpaceManager is collected. - BlockFreelist* _block_freelists; - - private: - // Accessors - Metachunk* chunk_list() const { return _chunk_list; } - - BlockFreelist* block_freelists() const { return _block_freelists; } - - Metaspace::MetadataType mdtype() { return _mdtype; } + // size_t _overhead_words; + // size_t _capacity_words; + // size_t _used_words; + uintx _num_chunks_by_level[chklvl::NUM_CHUNK_LEVELS]; + uintx _num_chunks_total; + + + Mutex* lock() const { return _lock; } + ChunkManager* chunk_manager() const { return _chunk_manager; } + const ChunkAllocSequence* chunk_alloc_sequence() const { return _chunk_alloc_sequence; } - VirtualSpaceList* vs_list() const { return Metaspace::get_space_list(_mdtype); } - ChunkManager* chunk_manager() const { return Metaspace::get_chunk_manager(_mdtype); } + BlockFreelist* block_freelist() const { return _block_freelist; } + void create_block_freelist(); - Metachunk* current_chunk() const { return _current_chunk; } - void set_current_chunk(Metachunk* v) { - _current_chunk = v; - } - - Metachunk* find_current_chunk(size_t word_size); - - // Add chunk to the list of chunks in use - void add_chunk(Metachunk* v, bool make_current); + // The current chunk is unable to service a request. The remainder of the chunk is + // chopped into blocks and fed into the _block_freelists, in the hope of later reuse. void retire_current_chunk(); - Mutex* lock() const { return _lock; } + // Given a requested word size, will allocate a chunk large enough to at least fit that + // size, but may be larger according to the rules in the ChunkAllocSequence. + // Updates counters and adds the chunk to the head of the chunk list. + Metachunk* allocate_chunk_to_fit(size_t requested_word_size); - // Adds to the given statistic object. Expects to be locked with lock(). - void add_to_statistics_locked(SpaceManagerStatistics* out) const; +public: - // Verify internal counters against the current state. Expects to be locked with lock(). - DEBUG_ONLY(void verify_metrics_locked() const;) + SpaceManager(ChunkManager* chunk_manager, const ChunkAllocSequence* alloc_sequence, Mutex* lock); - public: - SpaceManager(Metaspace::MetadataType mdtype, - Metaspace::MetaspaceType space_type, - Mutex* lock); ~SpaceManager(); - enum ChunkMultiples { - MediumChunkMultiple = 4 - }; - - static size_t specialized_chunk_size(bool is_class) { return is_class ? ClassSpecializedChunk : SpecializedChunk; } - static size_t small_chunk_size(bool is_class) { return is_class ? ClassSmallChunk : SmallChunk; } - static size_t medium_chunk_size(bool is_class) { return is_class ? ClassMediumChunk : MediumChunk; } - - static size_t smallest_chunk_size(bool is_class) { return specialized_chunk_size(is_class); } - - // Accessors - bool is_class() const { return _mdtype == Metaspace::ClassType; } - - size_t specialized_chunk_size() const { return specialized_chunk_size(is_class()); } - size_t small_chunk_size() const { return small_chunk_size(is_class()); } - size_t medium_chunk_size() const { return medium_chunk_size(is_class()); } - - size_t smallest_chunk_size() const { return smallest_chunk_size(is_class()); } - - size_t medium_chunk_bunch() const { return medium_chunk_size() * MediumChunkMultiple; } - - bool is_humongous(size_t word_size) { return word_size > medium_chunk_size(); } - - size_t capacity_words() const { return _capacity_words; } - size_t used_words() const { return _used_words; } - size_t overhead_words() const { return _overhead_words; } - - // Adjust local, global counters after a new chunk has been added. - void account_for_new_chunk(const Metachunk* new_chunk); - - // Adjust local, global counters after space has been allocated from the current chunk. - void account_for_allocation(size_t words); - - // Adjust global counters just before the SpaceManager dies, after all its chunks - // have been returned to the freelist. - void account_for_spacemanager_death(); - - // Adjust the initial chunk size to match one of the fixed chunk list sizes, - // or return the unadjusted size if the requested size is humongous. - static size_t adjust_initial_chunk_size(size_t requested, bool is_class_space); - size_t adjust_initial_chunk_size(size_t requested) const; - - // Get the initial chunks size for this metaspace type. - size_t get_initial_chunk_size(Metaspace::MetaspaceType type) const; - - // Todo: remove this once we have counters by chunk type. - uintx num_chunks_by_type(ChunkIndex chunk_type) const { return _num_chunks_by_type[chunk_type]; } - - Metachunk* get_new_chunk(size_t chunk_word_size); - - // Block allocation and deallocation. - // Allocates a block from the current chunk + // Allocate memory from Metaspace. Will attempt to allocate from the _block_freelists, + // failing that, from the current chunk; failing that, attempt to get a new chunk from + // the associated ChunkManager. MetaWord* allocate(size_t word_size); - // Helper for allocations - MetaWord* allocate_work(size_t word_size); - - // Returns a block to the per manager freelist + // Prematurely returns a metaspace allocation to the _block_freelists because it is not + // needed anymore. void deallocate(MetaWord* p, size_t word_size); - // Based on the allocation size and a minimum chunk size, - // returned chunk size (for expanding space for chunk allocation). - size_t calc_chunk_size(size_t allocation_word_size); - - // Called when an allocation from the current chunk fails. - // Gets a new chunk (may require getting a new virtual space), - // and allocates from that chunk. - MetaWord* grow_and_allocate(size_t word_size); - - // Notify memory usage to MemoryService. - void track_metaspace_memory_usage(); - - // debugging support. - - void print_on(outputStream* st) const; - void locked_print_chunks_in_use_on(outputStream* st) const; - - void verify(); - void verify_chunk_size(Metachunk* chunk); - - // This adjusts the size given to be greater than the minimum allocation size in - // words for data in metaspace. Esentially the minimum size is currently 3 words. - size_t get_allocation_word_size(size_t word_size) { - size_t byte_size = word_size * BytesPerWord; - - size_t raw_bytes_size = MAX2(byte_size, sizeof(Metablock)); - raw_bytes_size = align_up(raw_bytes_size, Metachunk::object_alignment()); - - size_t raw_word_size = raw_bytes_size / BytesPerWord; - assert(raw_word_size * BytesPerWord == raw_bytes_size, "Size problem"); - - return raw_word_size; - } - - // Adds to the given statistic object. + // Update statistics. This walks all in-use chunks. void add_to_statistics(SpaceManagerStatistics* out) const; - // Verify internal counters against the current state. - DEBUG_ONLY(void verify_metrics() const;) + // Run verifications. slow=true: verify chunk-internal integrity too. + DEBUG_ONLY(void locked_verify(bool slow) const;) }; - } // namespace metaspace #endif // SHARE_MEMORY_METASPACE_SPACEMANAGER_HPP