Path: blob/master/src/hotspot/share/memory/metaspace/binList.hpp
40957 views
/*1* Copyright (c) 2020, Oracle and/or its affiliates. All rights reserved.2* Copyright (c) 2020 SAP SE. All rights reserved.3* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.4*5* This code is free software; you can redistribute it and/or modify it6* under the terms of the GNU General Public License version 2 only, as7* published by the Free Software Foundation.8*9* This code is distributed in the hope that it will be useful, but WITHOUT10* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or11* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License12* version 2 for more details (a copy is included in the LICENSE file that13* accompanied this code).14*15* You should have received a copy of the GNU General Public License version16* 2 along with this work; if not, write to the Free Software Foundation,17* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.18*19* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA20* or visit www.oracle.com if you need additional information or have any21* questions.22*23*/2425#ifndef SHARE_MEMORY_METASPACE_BINLIST_HPP26#define SHARE_MEMORY_METASPACE_BINLIST_HPP2728#include "memory/metaspace/counters.hpp"29#include "memory/metaspace/metaspaceCommon.hpp"30#include "utilities/align.hpp"31#include "utilities/debug.hpp"32#include "utilities/globalDefinitions.hpp"3334namespace metaspace {3536// BinList is a data structure to manage small to very small memory blocks37// (only a few words). It is used to manage deallocated blocks - see38// class FreeBlocks.3940// Memory blocks are kept in linked lists. Each list41// contains blocks of only one size. There is a list for blocks of two words,42// for blocks of three words, etc. The list heads are kept in a vector,43// ordered by block size.44//4546// wordsize47//48// +---+ +---+ +---+ +---+49// 1 | |-->| |-->| |-...->| |50// +---+ +---+ +---+ +---+51//52// +----+ +----+ +----+ +----+53// 2 | |-->| |-->| |-...->| |54// +----+ +----+ +----+ +----+55//56// +-----+ +-----+ +-----+ +-----+57// 3 | |-->| |-->| |-...->| |58// +-----+ +-----+ +-----+ +-----+59// .60// .61// .62//63// +----------+ +----------+ +----------+ +----------+64// n | |-->| |-->| |-...->| |65// +----------+ +----------+ +----------+ +----------+6667// Insertion is of course fast, O(1).68//69// On retrieval, we attempt to find the closest fit to a given size, walking the70// list head vector (a bitmask is used to speed that part up).71//72// This structure is a bit expensive in memory costs (we pay one pointer per managed73// block size) so we only use it for a small number of sizes.7475template <size_t smallest_word_size, int num_lists>76class BinListImpl {7778struct Block {79Block* const _next;80const size_t _word_size;81Block(Block* next, size_t word_size) :82_next(next),83_word_size(word_size)84{}85};8687#define BLOCK_FORMAT "Block @" PTR_FORMAT ": size: " SIZE_FORMAT ", next: " PTR_FORMAT88#define BLOCK_FORMAT_ARGS(b) p2i(b), (b)->_word_size, p2i((b)->_next)8990// Smallest block size must be large enough to hold a Block structure.91STATIC_ASSERT(smallest_word_size * sizeof(MetaWord) >= sizeof(Block));92STATIC_ASSERT(num_lists > 0);9394public:9596// Minimal word size a block must have to be manageable by this structure.97const static size_t MinWordSize = smallest_word_size;9899// Maximal (incl) word size a block can have to be manageable by this structure.100const static size_t MaxWordSize = MinWordSize + num_lists - 1;101102private:103104Block* _blocks[num_lists];105106MemRangeCounter _counter;107108static int index_for_word_size(size_t word_size) {109int index = (int)(word_size - MinWordSize);110assert(index >= 0 && index < num_lists, "Invalid index %d", index);111return index;112}113114static size_t word_size_for_index(int index) {115assert(index >= 0 && index < num_lists, "Invalid index %d", index);116return MinWordSize + index;117}118119// Search the range [index, _num_lists) for the smallest non-empty list. Returns -1 on fail.120int index_for_next_non_empty_list(int index) {121assert(index >= 0 && index < num_lists, "Invalid index %d", index);122int i2 = index;123while (i2 < num_lists && _blocks[i2] == NULL) {124i2 ++;125}126return i2 == num_lists ? -1 : i2;127}128129public:130131BinListImpl() {132for (int i = 0; i < num_lists; i++) {133_blocks[i] = NULL;134}135}136137void add_block(MetaWord* p, size_t word_size) {138assert(word_size >= MinWordSize &&139word_size <= MaxWordSize, "bad block size");140const int index = index_for_word_size(word_size);141Block* old_head = _blocks[index];142Block* new_head = new(p)Block(old_head, word_size);143_blocks[index] = new_head;144_counter.add(word_size);145}146147// Given a word_size, searches and returns a block of at least that size.148// Block may be larger. Real block size is returned in *p_real_word_size.149MetaWord* remove_block(size_t word_size, size_t* p_real_word_size) {150assert(word_size >= MinWordSize &&151word_size <= MaxWordSize, "bad block size " SIZE_FORMAT ".", word_size);152int index = index_for_word_size(word_size);153index = index_for_next_non_empty_list(index);154if (index != -1) {155Block* b = _blocks[index];156const size_t real_word_size = word_size_for_index(index);157assert(b != NULL, "Sanity");158assert(b->_word_size >= word_size &&159b->_word_size == real_word_size,160"bad block size in list[%d] (" BLOCK_FORMAT ")", index, BLOCK_FORMAT_ARGS(b));161_blocks[index] = b->_next;162_counter.sub(real_word_size);163*p_real_word_size = real_word_size;164return (MetaWord*)b;165} else {166*p_real_word_size = 0;167return NULL;168}169}170171// Returns number of blocks in this structure172unsigned count() const { return _counter.count(); }173174// Returns total size, in words, of all elements.175size_t total_size() const { return _counter.total_size(); }176177bool is_empty() const { return count() == 0; }178179#ifdef ASSERT180void verify() const {181MemRangeCounter local_counter;182for (int i = 0; i < num_lists; i++) {183const size_t s = MinWordSize + i;184int pos = 0;185for (Block* b = _blocks[i]; b != NULL; b = b->_next, pos++) {186assert(b->_word_size == s,187"bad block size in list[%d] at pos %d (" BLOCK_FORMAT ")",188i, pos, BLOCK_FORMAT_ARGS(b));189local_counter.add(s);190}191}192local_counter.check(_counter);193}194#endif // ASSERT195196};197198typedef BinListImpl<2, 32> BinList32;199200} // namespace metaspace201202#endif // SHARE_MEMORY_METASPACE_BINLIST_HPP203204205