2007-12-01 00:00:00 +00:00
|
|
|
/*
|
2012-10-09 10:09:34 -07:00
|
|
|
* Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
|
2007-12-01 00:00:00 +00:00
|
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
|
|
*
|
|
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
|
|
* published by the Free Software Foundation.
|
|
|
|
*
|
|
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
|
|
* accompanied this code).
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License version
|
|
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
|
|
*
|
2010-05-27 19:08:38 -07:00
|
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
|
|
* questions.
|
2007-12-01 00:00:00 +00:00
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
2012-03-29 19:46:24 -07:00
|
|
|
#ifndef SHARE_VM_MEMORY_FREELIST_HPP
|
|
|
|
#define SHARE_VM_MEMORY_FREELIST_HPP
|
2010-11-23 13:22:55 -08:00
|
|
|
|
|
|
|
#include "gc_implementation/shared/allocationStats.hpp"
|
|
|
|
|
2007-12-01 00:00:00 +00:00
|
|
|
class CompactibleFreeListSpace;
|
|
|
|
|
2012-03-29 19:46:24 -07:00
|
|
|
// A class for maintaining a free list of Chunk's. The FreeList
|
2007-12-01 00:00:00 +00:00
|
|
|
// maintains a the structure of the list (head, tail, etc.) plus
|
|
|
|
// statistics for allocations from the list. The links between items
|
|
|
|
// are not part of FreeList. The statistics are
|
2012-03-29 19:46:24 -07:00
|
|
|
// used to make decisions about coalescing Chunk's when they
|
2007-12-01 00:00:00 +00:00
|
|
|
// are swept during collection.
|
|
|
|
//
|
|
|
|
// See the corresponding .cpp file for a description of the specifics
|
|
|
|
// for that implementation.
|
|
|
|
|
|
|
|
class Mutex;
|
2012-03-29 19:46:24 -07:00
|
|
|
template <class Chunk> class TreeList;
|
|
|
|
template <class Chunk> class PrintTreeCensusClosure;
|
2007-12-01 00:00:00 +00:00
|
|
|
|
2012-03-29 19:46:24 -07:00
|
|
|
template <class Chunk>
|
2007-12-01 00:00:00 +00:00
|
|
|
class FreeList VALUE_OBJ_CLASS_SPEC {
|
|
|
|
friend class CompactibleFreeListSpace;
|
2008-05-09 08:55:13 -07:00
|
|
|
friend class VMStructs;
|
2012-03-29 19:46:24 -07:00
|
|
|
friend class PrintTreeCensusClosure<Chunk>;
|
2009-12-23 09:23:54 -08:00
|
|
|
|
|
|
|
private:
|
2012-03-29 19:46:24 -07:00
|
|
|
Chunk* _head; // Head of list of free chunks
|
|
|
|
Chunk* _tail; // Tail of list of free chunks
|
2009-12-23 09:23:54 -08:00
|
|
|
size_t _size; // Size in Heap words of each chunk
|
2007-12-01 00:00:00 +00:00
|
|
|
ssize_t _count; // Number of entries in list
|
|
|
|
size_t _hint; // next larger size list with a positive surplus
|
|
|
|
|
2009-12-23 09:23:54 -08:00
|
|
|
AllocationStats _allocation_stats; // allocation-related statistics
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
#ifdef ASSERT
|
|
|
|
Mutex* _protecting_lock;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Asserts false if the protecting lock (if any) is not held.
|
|
|
|
void assert_proper_lock_protection_work() const PRODUCT_RETURN;
|
|
|
|
void assert_proper_lock_protection() const {
|
|
|
|
#ifdef ASSERT
|
|
|
|
if (_protecting_lock != NULL)
|
|
|
|
assert_proper_lock_protection_work();
|
|
|
|
#endif
|
|
|
|
}
|
|
|
|
|
|
|
|
// Initialize the allocation statistics.
|
|
|
|
protected:
|
2009-12-23 09:23:54 -08:00
|
|
|
void init_statistics(bool split_birth = false);
|
2007-12-01 00:00:00 +00:00
|
|
|
void set_count(ssize_t v) { _count = v;}
|
2009-12-23 09:23:54 -08:00
|
|
|
void increment_count() {
|
|
|
|
_count++;
|
|
|
|
}
|
|
|
|
|
2007-12-01 00:00:00 +00:00
|
|
|
void decrement_count() {
|
|
|
|
_count--;
|
2008-02-29 14:42:56 -08:00
|
|
|
assert(_count >= 0, "Count should not be negative");
|
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
public:
|
|
|
|
// Constructor
|
|
|
|
// Construct a list without any entries.
|
|
|
|
FreeList();
|
|
|
|
// Construct a list with "fc" as the first (and lone) entry in the list.
|
2012-03-29 19:46:24 -07:00
|
|
|
FreeList(Chunk* fc);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Reset the head, tail, hint, and count of a free list.
|
|
|
|
void reset(size_t hint);
|
|
|
|
|
|
|
|
// Declare the current free list to be protected by the given lock.
|
|
|
|
#ifdef ASSERT
|
|
|
|
void set_protecting_lock(Mutex* protecting_lock) {
|
|
|
|
_protecting_lock = protecting_lock;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Accessors.
|
2012-03-29 19:46:24 -07:00
|
|
|
Chunk* head() const {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
return _head;
|
|
|
|
}
|
2012-03-29 19:46:24 -07:00
|
|
|
void set_head(Chunk* v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
_head = v;
|
|
|
|
assert(!_head || _head->size() == _size, "bad chunk size");
|
|
|
|
}
|
|
|
|
// Set the head of the list and set the prev field of non-null
|
|
|
|
// values to NULL.
|
2012-03-29 19:46:24 -07:00
|
|
|
void link_head(Chunk* v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
set_head(v);
|
|
|
|
// If this method is not used (just set the head instead),
|
|
|
|
// this check can be avoided.
|
|
|
|
if (v != NULL) {
|
2012-04-25 09:55:55 -07:00
|
|
|
v->link_prev(NULL);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-29 19:46:24 -07:00
|
|
|
Chunk* tail() const {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
return _tail;
|
|
|
|
}
|
2012-03-29 19:46:24 -07:00
|
|
|
void set_tail(Chunk* v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
_tail = v;
|
|
|
|
assert(!_tail || _tail->size() == _size, "bad chunk size");
|
|
|
|
}
|
|
|
|
// Set the tail of the list and set the next field of non-null
|
|
|
|
// values to NULL.
|
2012-03-29 19:46:24 -07:00
|
|
|
void link_tail(Chunk* v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
set_tail(v);
|
|
|
|
if (v != NULL) {
|
2012-04-25 09:55:55 -07:00
|
|
|
v->clear_next();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// No locking checks in read-accessors: lock-free reads (only) are benign.
|
|
|
|
// Readers are expected to have the lock if they are doing work that
|
|
|
|
// requires atomicity guarantees in sections of code.
|
|
|
|
size_t size() const {
|
|
|
|
return _size;
|
|
|
|
}
|
|
|
|
void set_size(size_t v) {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
_size = v;
|
|
|
|
}
|
|
|
|
ssize_t count() const {
|
|
|
|
return _count;
|
|
|
|
}
|
|
|
|
size_t hint() const {
|
|
|
|
return _hint;
|
|
|
|
}
|
|
|
|
void set_hint(size_t v) {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
assert(v == 0 || _size < v, "Bad hint"); _hint = v;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Accessors for statistics
|
|
|
|
AllocationStats* allocation_stats() {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
return &_allocation_stats;
|
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t desired() const {
|
|
|
|
return _allocation_stats.desired();
|
|
|
|
}
|
2008-02-29 14:42:56 -08:00
|
|
|
void set_desired(ssize_t v) {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
_allocation_stats.set_desired(v);
|
|
|
|
}
|
2007-12-01 00:00:00 +00:00
|
|
|
void compute_desired(float inter_sweep_current,
|
2009-12-23 09:23:54 -08:00
|
|
|
float inter_sweep_estimate,
|
|
|
|
float intra_sweep_estimate) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
|
|
|
_allocation_stats.compute_desired(_count,
|
|
|
|
inter_sweep_current,
|
2009-12-23 09:23:54 -08:00
|
|
|
inter_sweep_estimate,
|
|
|
|
intra_sweep_estimate);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t coal_desired() const {
|
|
|
|
return _allocation_stats.coal_desired();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_coal_desired(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_coal_desired(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
ssize_t surplus() const {
|
|
|
|
return _allocation_stats.surplus();
|
|
|
|
}
|
|
|
|
void set_surplus(ssize_t v) {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
_allocation_stats.set_surplus(v);
|
|
|
|
}
|
|
|
|
void increment_surplus() {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
_allocation_stats.increment_surplus();
|
|
|
|
}
|
|
|
|
void decrement_surplus() {
|
|
|
|
assert_proper_lock_protection();
|
|
|
|
_allocation_stats.decrement_surplus();
|
|
|
|
}
|
|
|
|
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t bfr_surp() const {
|
|
|
|
return _allocation_stats.bfr_surp();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_bfr_surp(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_bfr_surp(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t prev_sweep() const {
|
|
|
|
return _allocation_stats.prev_sweep();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_prev_sweep(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_prev_sweep(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t before_sweep() const {
|
|
|
|
return _allocation_stats.before_sweep();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_before_sweep(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_before_sweep(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t coal_births() const {
|
|
|
|
return _allocation_stats.coal_births();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_coal_births(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_coal_births(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void increment_coal_births() {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.increment_coal_births();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t coal_deaths() const {
|
|
|
|
return _allocation_stats.coal_deaths();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_coal_deaths(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_coal_deaths(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void increment_coal_deaths() {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.increment_coal_deaths();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t split_births() const {
|
|
|
|
return _allocation_stats.split_births();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_split_births(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_split_births(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void increment_split_births() {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.increment_split_births();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
2012-04-25 09:55:55 -07:00
|
|
|
ssize_t split_deaths() const {
|
|
|
|
return _allocation_stats.split_deaths();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void set_split_deaths(ssize_t v) {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.set_split_deaths(v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
2012-04-25 09:55:55 -07:00
|
|
|
void increment_split_deaths() {
|
2007-12-01 00:00:00 +00:00
|
|
|
assert_proper_lock_protection();
|
2012-04-25 09:55:55 -07:00
|
|
|
_allocation_stats.increment_split_deaths();
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
NOT_PRODUCT(
|
2012-04-25 09:55:55 -07:00
|
|
|
// For debugging. The "_returned_bytes" in all the lists are summed
|
2007-12-01 00:00:00 +00:00
|
|
|
// and compared with the total number of bytes swept during a
|
|
|
|
// collection.
|
2012-04-25 09:55:55 -07:00
|
|
|
size_t returned_bytes() const { return _allocation_stats.returned_bytes(); }
|
|
|
|
void set_returned_bytes(size_t v) { _allocation_stats.set_returned_bytes(v); }
|
|
|
|
void increment_returned_bytes_by(size_t v) {
|
|
|
|
_allocation_stats.set_returned_bytes(_allocation_stats.returned_bytes() + v);
|
2007-12-01 00:00:00 +00:00
|
|
|
}
|
|
|
|
)
|
|
|
|
|
|
|
|
// Unlink head of list and return it. Returns NULL if
|
|
|
|
// the list is empty.
|
2012-04-25 09:55:55 -07:00
|
|
|
Chunk* get_chunk_at_head();
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Remove the first "n" or "count", whichever is smaller, chunks from the
|
|
|
|
// list, setting "fl", which is required to be empty, to point to them.
|
2012-03-29 19:46:24 -07:00
|
|
|
void getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Unlink this chunk from it's free list
|
2012-04-25 09:55:55 -07:00
|
|
|
void remove_chunk(Chunk* fc);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Add this chunk to this free list.
|
2012-04-25 09:55:55 -07:00
|
|
|
void return_chunk_at_head(Chunk* fc);
|
|
|
|
void return_chunk_at_tail(Chunk* fc);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Similar to returnChunk* but also records some diagnostic
|
|
|
|
// information.
|
2012-04-25 09:55:55 -07:00
|
|
|
void return_chunk_at_head(Chunk* fc, bool record_return);
|
|
|
|
void return_chunk_at_tail(Chunk* fc, bool record_return);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Prepend "fl" (whose size is required to be the same as that of "this")
|
|
|
|
// to the front of "this" list.
|
2012-03-29 19:46:24 -07:00
|
|
|
void prepend(FreeList<Chunk>* fl);
|
2007-12-01 00:00:00 +00:00
|
|
|
|
|
|
|
// Verify that the chunk is in the list.
|
|
|
|
// found. Return NULL if "fc" is not found.
|
2012-04-25 09:55:55 -07:00
|
|
|
bool verify_chunk_in_free_list(Chunk* fc) const;
|
2008-02-29 14:42:56 -08:00
|
|
|
|
2009-12-23 09:23:54 -08:00
|
|
|
// Stats verification
|
|
|
|
void verify_stats() const PRODUCT_RETURN;
|
|
|
|
|
2008-02-29 14:42:56 -08:00
|
|
|
// Printing support
|
|
|
|
static void print_labels_on(outputStream* st, const char* c);
|
|
|
|
void print_on(outputStream* st, const char* c = NULL) const;
|
2007-12-01 00:00:00 +00:00
|
|
|
};
|
2010-11-23 13:22:55 -08:00
|
|
|
|
2012-03-29 19:46:24 -07:00
|
|
|
#endif // SHARE_VM_MEMORY_FREELIST_HPP
|