mirror of
https://github.com/openjdk/jdk.git
synced 2025-08-28 15:24:43 +02:00
7045397: NPG: Add freelists to class loader arenas
Reviewed-by: coleenp, stefank, jprovino, ohair
This commit is contained in:
parent
8277d1355e
commit
37bddeb62b
20 changed files with 1547 additions and 1223 deletions
|
@ -79,10 +79,10 @@ ifeq ($(INCLUDE_ALTERNATE_GCS), false)
|
||||||
CXXFLAGS += -DSERIALGC
|
CXXFLAGS += -DSERIALGC
|
||||||
CFLAGS += -DSERIALGC
|
CFLAGS += -DSERIALGC
|
||||||
Src_Files_EXCLUDE += \
|
Src_Files_EXCLUDE += \
|
||||||
binaryTreeDictionary.cpp cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \
|
cmsAdaptiveSizePolicy.cpp cmsCollectorPolicy.cpp \
|
||||||
cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp cmsPermGen.cpp compactibleFreeListSpace.cpp \
|
cmsGCAdaptivePolicyCounters.cpp cmsLockVerifier.cpp cmsPermGen.cpp compactibleFreeListSpace.cpp \
|
||||||
concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp freeBlockDictionary.cpp \
|
concurrentMarkSweepGeneration.cpp concurrentMarkSweepThread.cpp \
|
||||||
freeChunk.cpp freeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \
|
freeChunk.cpp adaptiveFreeList.cpp promotionInfo.cpp vmCMSOperations.cpp collectionSetChooser.cpp \
|
||||||
concurrentG1Refine.cpp concurrentG1RefineThread.cpp concurrentMark.cpp concurrentMarkThread.cpp \
|
concurrentG1Refine.cpp concurrentG1RefineThread.cpp concurrentMark.cpp concurrentMarkThread.cpp \
|
||||||
dirtyCardQueue.cpp g1AllocRegion.cpp g1BlockOffsetTable.cpp g1CollectedHeap.cpp g1GCPhaseTimes.cpp \
|
dirtyCardQueue.cpp g1AllocRegion.cpp g1BlockOffsetTable.cpp g1CollectedHeap.cpp g1GCPhaseTimes.cpp \
|
||||||
g1CollectorPolicy.cpp g1ErgoVerbose.cpp g1_globals.cpp g1HRPrinter.cpp g1MarkSweep.cpp \
|
g1CollectorPolicy.cpp g1ErgoVerbose.cpp g1_globals.cpp g1HRPrinter.cpp g1MarkSweep.cpp \
|
||||||
|
|
|
@ -0,0 +1,175 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "precompiled.hpp"
|
||||||
|
#include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp"
|
||||||
|
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
||||||
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
|
#include "memory/sharedHeap.hpp"
|
||||||
|
#include "runtime/globals.hpp"
|
||||||
|
#include "runtime/mutex.hpp"
|
||||||
|
#include "runtime/vmThread.hpp"
|
||||||
|
|
||||||
|
template <>
|
||||||
|
void AdaptiveFreeList<FreeChunk>::print_on(outputStream* st, const char* c) const {
|
||||||
|
if (c != NULL) {
|
||||||
|
st->print("%16s", c);
|
||||||
|
} else {
|
||||||
|
st->print(SIZE_FORMAT_W(16), size());
|
||||||
|
}
|
||||||
|
st->print("\t"
|
||||||
|
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t"
|
||||||
|
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\n",
|
||||||
|
bfr_surp(), surplus(), desired(), prev_sweep(), before_sweep(),
|
||||||
|
count(), coal_births(), coal_deaths(), split_births(), split_deaths());
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
AdaptiveFreeList<Chunk>::AdaptiveFreeList() : FreeList<Chunk>(), _hint(0) {
|
||||||
|
init_statistics();
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
AdaptiveFreeList<Chunk>::AdaptiveFreeList(Chunk* fc) : FreeList<Chunk>(fc), _hint(0) {
|
||||||
|
init_statistics();
|
||||||
|
#ifndef PRODUCT
|
||||||
|
_allocation_stats.set_returned_bytes(size() * HeapWordSize);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::initialize() {
|
||||||
|
FreeList<Chunk>::initialize();
|
||||||
|
set_hint(0);
|
||||||
|
init_statistics(true /* split_birth */);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::reset(size_t hint) {
|
||||||
|
FreeList<Chunk>::reset();
|
||||||
|
set_hint(hint);
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::assert_proper_lock_protection_work() const {
|
||||||
|
assert(protecting_lock() != NULL, "Don't call this directly");
|
||||||
|
assert(ParallelGCThreads > 0, "Don't call this directly");
|
||||||
|
Thread* thr = Thread::current();
|
||||||
|
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
|
||||||
|
// assert that we are holding the freelist lock
|
||||||
|
} else if (thr->is_GC_task_thread()) {
|
||||||
|
assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
|
||||||
|
} else if (thr->is_Java_thread()) {
|
||||||
|
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
|
||||||
|
} else {
|
||||||
|
ShouldNotReachHere(); // unaccounted thread type?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::init_statistics(bool split_birth) {
|
||||||
|
_allocation_stats.initialize(split_birth);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
size_t AdaptiveFreeList<Chunk>::get_better_size() {
|
||||||
|
|
||||||
|
// A candidate chunk has been found. If it is already under
|
||||||
|
// populated and there is a hinT, REturn the hint(). Else
|
||||||
|
// return the size of this chunk.
|
||||||
|
if (surplus() <= 0) {
|
||||||
|
if (hint() != 0) {
|
||||||
|
return hint();
|
||||||
|
} else {
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// This list has a surplus so use it.
|
||||||
|
return size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::return_chunk_at_head(Chunk* chunk) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
return_chunk_at_head(chunk, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
|
||||||
|
FreeList<Chunk>::return_chunk_at_head(chunk, record_return);
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (record_return) {
|
||||||
|
increment_returned_bytes_by(size()*HeapWordSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::return_chunk_at_tail(Chunk* chunk) {
|
||||||
|
return_chunk_at_tail(chunk, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
|
||||||
|
FreeList<Chunk>::return_chunk_at_tail(chunk, record_return);
|
||||||
|
#ifdef ASSERT
|
||||||
|
if (record_return) {
|
||||||
|
increment_returned_bytes_by(size()*HeapWordSize);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
template <class Chunk>
|
||||||
|
void AdaptiveFreeList<Chunk>::verify_stats() const {
|
||||||
|
// The +1 of the LH comparand is to allow some "looseness" in
|
||||||
|
// checking: we usually call this interface when adding a block
|
||||||
|
// and we'll subsequently update the stats; we cannot update the
|
||||||
|
// stats beforehand because in the case of the large-block BT
|
||||||
|
// dictionary for example, this might be the first block and
|
||||||
|
// in that case there would be no place that we could record
|
||||||
|
// the stats (which are kept in the block itself).
|
||||||
|
assert((_allocation_stats.prev_sweep() + _allocation_stats.split_births()
|
||||||
|
+ _allocation_stats.coal_births() + 1) // Total Production Stock + 1
|
||||||
|
>= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths()
|
||||||
|
+ (ssize_t)count()), // Total Current Stock + depletion
|
||||||
|
err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT
|
||||||
|
" violates Conservation Principle: "
|
||||||
|
"prev_sweep(" SIZE_FORMAT ")"
|
||||||
|
" + split_births(" SIZE_FORMAT ")"
|
||||||
|
" + coal_births(" SIZE_FORMAT ") + 1 >= "
|
||||||
|
" split_deaths(" SIZE_FORMAT ")"
|
||||||
|
" coal_deaths(" SIZE_FORMAT ")"
|
||||||
|
" + count(" SSIZE_FORMAT ")",
|
||||||
|
this, size(), _allocation_stats.prev_sweep(), _allocation_stats.split_births(),
|
||||||
|
_allocation_stats.split_births(), _allocation_stats.split_deaths(),
|
||||||
|
_allocation_stats.coal_deaths(), count()));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Needs to be after the definitions have been seen.
|
||||||
|
template class AdaptiveFreeList<FreeChunk>;
|
|
@ -0,0 +1,232 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef SHARE_VM_MEMORY_ADAPTIVEFREELIST_HPP
|
||||||
|
#define SHARE_VM_MEMORY_ADAPTIVEFREELIST_HPP
|
||||||
|
|
||||||
|
#include "memory/freeList.hpp"
|
||||||
|
#include "gc_implementation/shared/allocationStats.hpp"
|
||||||
|
|
||||||
|
class CompactibleFreeListSpace;
|
||||||
|
|
||||||
|
// A class for maintaining a free list of Chunk's. The FreeList
|
||||||
|
// 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
|
||||||
|
// used to make decisions about coalescing Chunk's when they
|
||||||
|
// are swept during collection.
|
||||||
|
//
|
||||||
|
// See the corresponding .cpp file for a description of the specifics
|
||||||
|
// for that implementation.
|
||||||
|
|
||||||
|
class Mutex;
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
class AdaptiveFreeList : public FreeList<Chunk> {
|
||||||
|
friend class CompactibleFreeListSpace;
|
||||||
|
friend class VMStructs;
|
||||||
|
// friend class PrintTreeCensusClosure<Chunk, FreeList_t>;
|
||||||
|
|
||||||
|
size_t _hint; // next larger size list with a positive surplus
|
||||||
|
|
||||||
|
AllocationStats _allocation_stats; // allocation-related statistics
|
||||||
|
|
||||||
|
public:
|
||||||
|
|
||||||
|
AdaptiveFreeList();
|
||||||
|
AdaptiveFreeList(Chunk* fc);
|
||||||
|
|
||||||
|
using FreeList<Chunk>::assert_proper_lock_protection;
|
||||||
|
#ifdef ASSERT
|
||||||
|
using FreeList<Chunk>::protecting_lock;
|
||||||
|
#endif
|
||||||
|
using FreeList<Chunk>::count;
|
||||||
|
using FreeList<Chunk>::size;
|
||||||
|
using FreeList<Chunk>::verify_chunk_in_free_list;
|
||||||
|
using FreeList<Chunk>::getFirstNChunksFromList;
|
||||||
|
using FreeList<Chunk>::print_on;
|
||||||
|
void return_chunk_at_head(Chunk* fc, bool record_return);
|
||||||
|
void return_chunk_at_head(Chunk* fc);
|
||||||
|
void return_chunk_at_tail(Chunk* fc, bool record_return);
|
||||||
|
void return_chunk_at_tail(Chunk* fc);
|
||||||
|
using FreeList<Chunk>::return_chunk_at_tail;
|
||||||
|
using FreeList<Chunk>::remove_chunk;
|
||||||
|
using FreeList<Chunk>::prepend;
|
||||||
|
using FreeList<Chunk>::print_labels_on;
|
||||||
|
using FreeList<Chunk>::get_chunk_at_head;
|
||||||
|
|
||||||
|
// Initialize.
|
||||||
|
void initialize();
|
||||||
|
|
||||||
|
// Reset the head, tail, hint, and count of a free list.
|
||||||
|
void reset(size_t hint);
|
||||||
|
|
||||||
|
void assert_proper_lock_protection_work() const PRODUCT_RETURN;
|
||||||
|
|
||||||
|
void print_on(outputStream* st, const char* c = NULL) const;
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t get_better_size();
|
||||||
|
|
||||||
|
// Accessors for statistics
|
||||||
|
void init_statistics(bool split_birth = false);
|
||||||
|
|
||||||
|
AllocationStats* allocation_stats() {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
return &_allocation_stats;
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t desired() const {
|
||||||
|
return _allocation_stats.desired();
|
||||||
|
}
|
||||||
|
void set_desired(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_desired(v);
|
||||||
|
}
|
||||||
|
void compute_desired(float inter_sweep_current,
|
||||||
|
float inter_sweep_estimate,
|
||||||
|
float intra_sweep_estimate) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.compute_desired(count(),
|
||||||
|
inter_sweep_current,
|
||||||
|
inter_sweep_estimate,
|
||||||
|
intra_sweep_estimate);
|
||||||
|
}
|
||||||
|
ssize_t coal_desired() const {
|
||||||
|
return _allocation_stats.coal_desired();
|
||||||
|
}
|
||||||
|
void set_coal_desired(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_coal_desired(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t bfr_surp() const {
|
||||||
|
return _allocation_stats.bfr_surp();
|
||||||
|
}
|
||||||
|
void set_bfr_surp(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_bfr_surp(v);
|
||||||
|
}
|
||||||
|
ssize_t prev_sweep() const {
|
||||||
|
return _allocation_stats.prev_sweep();
|
||||||
|
}
|
||||||
|
void set_prev_sweep(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_prev_sweep(v);
|
||||||
|
}
|
||||||
|
ssize_t before_sweep() const {
|
||||||
|
return _allocation_stats.before_sweep();
|
||||||
|
}
|
||||||
|
void set_before_sweep(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_before_sweep(v);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t coal_births() const {
|
||||||
|
return _allocation_stats.coal_births();
|
||||||
|
}
|
||||||
|
void set_coal_births(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_coal_births(v);
|
||||||
|
}
|
||||||
|
void increment_coal_births() {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.increment_coal_births();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t coal_deaths() const {
|
||||||
|
return _allocation_stats.coal_deaths();
|
||||||
|
}
|
||||||
|
void set_coal_deaths(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_coal_deaths(v);
|
||||||
|
}
|
||||||
|
void increment_coal_deaths() {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.increment_coal_deaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t split_births() const {
|
||||||
|
return _allocation_stats.split_births();
|
||||||
|
}
|
||||||
|
void set_split_births(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_split_births(v);
|
||||||
|
}
|
||||||
|
void increment_split_births() {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.increment_split_births();
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t split_deaths() const {
|
||||||
|
return _allocation_stats.split_deaths();
|
||||||
|
}
|
||||||
|
void set_split_deaths(ssize_t v) {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.set_split_deaths(v);
|
||||||
|
}
|
||||||
|
void increment_split_deaths() {
|
||||||
|
assert_proper_lock_protection();
|
||||||
|
_allocation_stats.increment_split_deaths();
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef PRODUCT
|
||||||
|
// For debugging. The "_returned_bytes" in all the lists are summed
|
||||||
|
// and compared with the total number of bytes swept during a
|
||||||
|
// collection.
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
// Stats verification
|
||||||
|
void verify_stats() const;
|
||||||
|
#endif // NOT PRODUCT
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // SHARE_VM_MEMORY_ADAPTIVEFREELIST_HPP
|
|
@ -91,7 +91,7 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
|
||||||
_collector(NULL)
|
_collector(NULL)
|
||||||
{
|
{
|
||||||
assert(sizeof(FreeChunk) / BytesPerWord <= MinChunkSize,
|
assert(sizeof(FreeChunk) / BytesPerWord <= MinChunkSize,
|
||||||
"FreeChunk is larger than expected");
|
"FreeChunk is larger than expected");
|
||||||
_bt.set_space(this);
|
_bt.set_space(this);
|
||||||
initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
|
initialize(mr, SpaceDecorator::Clear, SpaceDecorator::Mangle);
|
||||||
// We have all of "mr", all of which we place in the dictionary
|
// We have all of "mr", all of which we place in the dictionary
|
||||||
|
@ -101,14 +101,14 @@ CompactibleFreeListSpace::CompactibleFreeListSpace(BlockOffsetSharedArray* bs,
|
||||||
// implementation, namely, the simple binary tree (splaying
|
// implementation, namely, the simple binary tree (splaying
|
||||||
// temporarily disabled).
|
// temporarily disabled).
|
||||||
switch (dictionaryChoice) {
|
switch (dictionaryChoice) {
|
||||||
|
case FreeBlockDictionary<FreeChunk>::dictionaryBinaryTree:
|
||||||
|
_dictionary = new BinaryTreeDictionary<FreeChunk, AdaptiveFreeList>(mr);
|
||||||
|
break;
|
||||||
case FreeBlockDictionary<FreeChunk>::dictionarySplayTree:
|
case FreeBlockDictionary<FreeChunk>::dictionarySplayTree:
|
||||||
case FreeBlockDictionary<FreeChunk>::dictionarySkipList:
|
case FreeBlockDictionary<FreeChunk>::dictionarySkipList:
|
||||||
default:
|
default:
|
||||||
warning("dictionaryChoice: selected option not understood; using"
|
warning("dictionaryChoice: selected option not understood; using"
|
||||||
" default BinaryTreeDictionary implementation instead.");
|
" default BinaryTreeDictionary implementation instead.");
|
||||||
case FreeBlockDictionary<FreeChunk>::dictionaryBinaryTree:
|
|
||||||
_dictionary = new BinaryTreeDictionary<FreeChunk>(mr, use_adaptive_freelists);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
assert(_dictionary != NULL, "CMS dictionary initialization");
|
assert(_dictionary != NULL, "CMS dictionary initialization");
|
||||||
// The indexed free lists are initially all empty and are lazily
|
// The indexed free lists are initially all empty and are lazily
|
||||||
|
@ -453,7 +453,7 @@ const {
|
||||||
reportIndexedFreeListStatistics();
|
reportIndexedFreeListStatistics();
|
||||||
gclog_or_tty->print_cr("Layout of Indexed Freelists");
|
gclog_or_tty->print_cr("Layout of Indexed Freelists");
|
||||||
gclog_or_tty->print_cr("---------------------------");
|
gclog_or_tty->print_cr("---------------------------");
|
||||||
FreeList<FreeChunk>::print_labels_on(st, "size");
|
AdaptiveFreeList<FreeChunk>::print_labels_on(st, "size");
|
||||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||||
_indexedFreeList[i].print_on(gclog_or_tty);
|
_indexedFreeList[i].print_on(gclog_or_tty);
|
||||||
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
|
for (FreeChunk* fc = _indexedFreeList[i].head(); fc != NULL;
|
||||||
|
@ -1319,7 +1319,7 @@ FreeChunk* CompactibleFreeListSpace::getChunkFromGreater(size_t numWords) {
|
||||||
size_t currSize = numWords + MinChunkSize;
|
size_t currSize = numWords + MinChunkSize;
|
||||||
assert(currSize % MinObjAlignment == 0, "currSize should be aligned");
|
assert(currSize % MinObjAlignment == 0, "currSize should be aligned");
|
||||||
for (i = currSize; i < IndexSetSize; i += IndexSetStride) {
|
for (i = currSize; i < IndexSetSize; i += IndexSetStride) {
|
||||||
FreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||||
if (fl->head()) {
|
if (fl->head()) {
|
||||||
ret = getFromListGreater(fl, numWords);
|
ret = getFromListGreater(fl, numWords);
|
||||||
assert(ret == NULL || ret->is_free(), "Should be returning a free chunk");
|
assert(ret == NULL || ret->is_free(), "Should be returning a free chunk");
|
||||||
|
@ -1702,7 +1702,9 @@ CompactibleFreeListSpace::returnChunkToDictionary(FreeChunk* chunk) {
|
||||||
_dictionary->return_chunk(chunk);
|
_dictionary->return_chunk(chunk);
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
|
if (CMSCollector::abstract_state() != CMSCollector::Sweeping) {
|
||||||
TreeChunk<FreeChunk>::as_TreeChunk(chunk)->list()->verify_stats();
|
TreeChunk<FreeChunk, AdaptiveFreeList>* tc = TreeChunk<FreeChunk, AdaptiveFreeList>::as_TreeChunk(chunk);
|
||||||
|
TreeList<FreeChunk, AdaptiveFreeList>* tl = tc->list();
|
||||||
|
tl->verify_stats();
|
||||||
}
|
}
|
||||||
#endif // PRODUCT
|
#endif // PRODUCT
|
||||||
}
|
}
|
||||||
|
@ -1745,7 +1747,7 @@ CompactibleFreeListSpace::addChunkToFreeListsAtEndRecordingStats(
|
||||||
{
|
{
|
||||||
MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag);
|
MutexLockerEx x(lock, Mutex::_no_safepoint_check_flag);
|
||||||
ec = dictionary()->find_largest_dict(); // get largest block
|
ec = dictionary()->find_largest_dict(); // get largest block
|
||||||
if (ec != NULL && ec->end() == chunk) {
|
if (ec != NULL && ec->end() == (uintptr_t*) chunk) {
|
||||||
// It's a coterminal block - we can coalesce.
|
// It's a coterminal block - we can coalesce.
|
||||||
size_t old_size = ec->size();
|
size_t old_size = ec->size();
|
||||||
coalDeath(old_size);
|
coalDeath(old_size);
|
||||||
|
@ -1850,11 +1852,11 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) {
|
||||||
the excess is >= MIN_CHUNK. */
|
the excess is >= MIN_CHUNK. */
|
||||||
size_t start = align_object_size(numWords + MinChunkSize);
|
size_t start = align_object_size(numWords + MinChunkSize);
|
||||||
if (start < IndexSetSize) {
|
if (start < IndexSetSize) {
|
||||||
FreeList<FreeChunk>* it = _indexedFreeList;
|
AdaptiveFreeList<FreeChunk>* it = _indexedFreeList;
|
||||||
size_t hint = _indexedFreeList[start].hint();
|
size_t hint = _indexedFreeList[start].hint();
|
||||||
while (hint < IndexSetSize) {
|
while (hint < IndexSetSize) {
|
||||||
assert(hint % MinObjAlignment == 0, "hint should be aligned");
|
assert(hint % MinObjAlignment == 0, "hint should be aligned");
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[hint];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[hint];
|
||||||
if (fl->surplus() > 0 && fl->head() != NULL) {
|
if (fl->surplus() > 0 && fl->head() != NULL) {
|
||||||
// Found a list with surplus, reset original hint
|
// Found a list with surplus, reset original hint
|
||||||
// and split out a free chunk which is returned.
|
// and split out a free chunk which is returned.
|
||||||
|
@ -1873,7 +1875,7 @@ FreeChunk* CompactibleFreeListSpace::bestFitSmall(size_t numWords) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Requires fl->size >= numWords + MinChunkSize */
|
/* Requires fl->size >= numWords + MinChunkSize */
|
||||||
FreeChunk* CompactibleFreeListSpace::getFromListGreater(FreeList<FreeChunk>* fl,
|
FreeChunk* CompactibleFreeListSpace::getFromListGreater(AdaptiveFreeList<FreeChunk>* fl,
|
||||||
size_t numWords) {
|
size_t numWords) {
|
||||||
FreeChunk *curr = fl->head();
|
FreeChunk *curr = fl->head();
|
||||||
size_t oldNumWords = curr->size();
|
size_t oldNumWords = curr->size();
|
||||||
|
@ -2155,7 +2157,7 @@ void CompactibleFreeListSpace::beginSweepFLCensus(
|
||||||
assert_locked();
|
assert_locked();
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||||
FreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[i];
|
||||||
if (PrintFLSStatistics > 1) {
|
if (PrintFLSStatistics > 1) {
|
||||||
gclog_or_tty->print("size[%d] : ", i);
|
gclog_or_tty->print("size[%d] : ", i);
|
||||||
}
|
}
|
||||||
|
@ -2174,7 +2176,7 @@ void CompactibleFreeListSpace::setFLSurplus() {
|
||||||
assert_locked();
|
assert_locked();
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||||
fl->set_surplus(fl->count() -
|
fl->set_surplus(fl->count() -
|
||||||
(ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent));
|
(ssize_t)((double)fl->desired() * CMSSmallSplitSurplusPercent));
|
||||||
}
|
}
|
||||||
|
@ -2185,7 +2187,7 @@ void CompactibleFreeListSpace::setFLHints() {
|
||||||
size_t i;
|
size_t i;
|
||||||
size_t h = IndexSetSize;
|
size_t h = IndexSetSize;
|
||||||
for (i = IndexSetSize - 1; i != 0; i -= IndexSetStride) {
|
for (i = IndexSetSize - 1; i != 0; i -= IndexSetStride) {
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||||
fl->set_hint(h);
|
fl->set_hint(h);
|
||||||
if (fl->surplus() > 0) {
|
if (fl->surplus() > 0) {
|
||||||
h = i;
|
h = i;
|
||||||
|
@ -2197,7 +2199,7 @@ void CompactibleFreeListSpace::clearFLCensus() {
|
||||||
assert_locked();
|
assert_locked();
|
||||||
size_t i;
|
size_t i;
|
||||||
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
for (i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||||
fl->set_prev_sweep(fl->count());
|
fl->set_prev_sweep(fl->count());
|
||||||
fl->set_coal_births(0);
|
fl->set_coal_births(0);
|
||||||
fl->set_coal_deaths(0);
|
fl->set_coal_deaths(0);
|
||||||
|
@ -2224,7 +2226,7 @@ void CompactibleFreeListSpace::endSweepFLCensus(size_t sweep_count) {
|
||||||
|
|
||||||
bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
||||||
if (size < SmallForDictionary) {
|
if (size < SmallForDictionary) {
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||||
return (fl->coal_desired() < 0) ||
|
return (fl->coal_desired() < 0) ||
|
||||||
((int)fl->count() > fl->coal_desired());
|
((int)fl->count() > fl->coal_desired());
|
||||||
} else {
|
} else {
|
||||||
|
@ -2234,14 +2236,14 @@ bool CompactibleFreeListSpace::coalOverPopulated(size_t size) {
|
||||||
|
|
||||||
void CompactibleFreeListSpace::smallCoalBirth(size_t size) {
|
void CompactibleFreeListSpace::smallCoalBirth(size_t size) {
|
||||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||||
fl->increment_coal_births();
|
fl->increment_coal_births();
|
||||||
fl->increment_surplus();
|
fl->increment_surplus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactibleFreeListSpace::smallCoalDeath(size_t size) {
|
void CompactibleFreeListSpace::smallCoalDeath(size_t size) {
|
||||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||||
fl->increment_coal_deaths();
|
fl->increment_coal_deaths();
|
||||||
fl->decrement_surplus();
|
fl->decrement_surplus();
|
||||||
}
|
}
|
||||||
|
@ -2250,7 +2252,7 @@ void CompactibleFreeListSpace::coalBirth(size_t size) {
|
||||||
if (size < SmallForDictionary) {
|
if (size < SmallForDictionary) {
|
||||||
smallCoalBirth(size);
|
smallCoalBirth(size);
|
||||||
} else {
|
} else {
|
||||||
dictionary()->dict_census_udpate(size,
|
dictionary()->dict_census_update(size,
|
||||||
false /* split */,
|
false /* split */,
|
||||||
true /* birth */);
|
true /* birth */);
|
||||||
}
|
}
|
||||||
|
@ -2260,7 +2262,7 @@ void CompactibleFreeListSpace::coalDeath(size_t size) {
|
||||||
if(size < SmallForDictionary) {
|
if(size < SmallForDictionary) {
|
||||||
smallCoalDeath(size);
|
smallCoalDeath(size);
|
||||||
} else {
|
} else {
|
||||||
dictionary()->dict_census_udpate(size,
|
dictionary()->dict_census_update(size,
|
||||||
false /* split */,
|
false /* split */,
|
||||||
false /* birth */);
|
false /* birth */);
|
||||||
}
|
}
|
||||||
|
@ -2268,14 +2270,14 @@ void CompactibleFreeListSpace::coalDeath(size_t size) {
|
||||||
|
|
||||||
void CompactibleFreeListSpace::smallSplitBirth(size_t size) {
|
void CompactibleFreeListSpace::smallSplitBirth(size_t size) {
|
||||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||||
fl->increment_split_births();
|
fl->increment_split_births();
|
||||||
fl->increment_surplus();
|
fl->increment_surplus();
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactibleFreeListSpace::smallSplitDeath(size_t size) {
|
void CompactibleFreeListSpace::smallSplitDeath(size_t size) {
|
||||||
assert(size < SmallForDictionary, "Size too large for indexed list");
|
assert(size < SmallForDictionary, "Size too large for indexed list");
|
||||||
FreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[size];
|
||||||
fl->increment_split_deaths();
|
fl->increment_split_deaths();
|
||||||
fl->decrement_surplus();
|
fl->decrement_surplus();
|
||||||
}
|
}
|
||||||
|
@ -2284,7 +2286,7 @@ void CompactibleFreeListSpace::split_birth(size_t size) {
|
||||||
if (size < SmallForDictionary) {
|
if (size < SmallForDictionary) {
|
||||||
smallSplitBirth(size);
|
smallSplitBirth(size);
|
||||||
} else {
|
} else {
|
||||||
dictionary()->dict_census_udpate(size,
|
dictionary()->dict_census_update(size,
|
||||||
true /* split */,
|
true /* split */,
|
||||||
true /* birth */);
|
true /* birth */);
|
||||||
}
|
}
|
||||||
|
@ -2294,7 +2296,7 @@ void CompactibleFreeListSpace::splitDeath(size_t size) {
|
||||||
if (size < SmallForDictionary) {
|
if (size < SmallForDictionary) {
|
||||||
smallSplitDeath(size);
|
smallSplitDeath(size);
|
||||||
} else {
|
} else {
|
||||||
dictionary()->dict_census_udpate(size,
|
dictionary()->dict_census_update(size,
|
||||||
true /* split */,
|
true /* split */,
|
||||||
false /* birth */);
|
false /* birth */);
|
||||||
}
|
}
|
||||||
|
@ -2517,10 +2519,10 @@ void CompactibleFreeListSpace::verifyIndexedFreeList(size_t size) const {
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
void CompactibleFreeListSpace::check_free_list_consistency() const {
|
void CompactibleFreeListSpace::check_free_list_consistency() const {
|
||||||
assert(_dictionary->min_size() <= IndexSetSize,
|
assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size() <= IndexSetSize),
|
||||||
"Some sizes can't be allocated without recourse to"
|
"Some sizes can't be allocated without recourse to"
|
||||||
" linear allocation buffers");
|
" linear allocation buffers");
|
||||||
assert(BinaryTreeDictionary<FreeChunk>::min_tree_chunk_size*HeapWordSize == sizeof(TreeChunk<FreeChunk>),
|
assert((TreeChunk<FreeChunk, AdaptiveFreeList>::min_size()*HeapWordSize == sizeof(TreeChunk<FreeChunk, AdaptiveFreeList>)),
|
||||||
"else MIN_TREE_CHUNK_SIZE is wrong");
|
"else MIN_TREE_CHUNK_SIZE is wrong");
|
||||||
assert(IndexSetStart != 0, "IndexSetStart not initialized");
|
assert(IndexSetStart != 0, "IndexSetStart not initialized");
|
||||||
assert(IndexSetStride != 0, "IndexSetStride not initialized");
|
assert(IndexSetStride != 0, "IndexSetStride not initialized");
|
||||||
|
@ -2529,15 +2531,15 @@ void CompactibleFreeListSpace::check_free_list_consistency() const {
|
||||||
|
|
||||||
void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
void CompactibleFreeListSpace::printFLCensus(size_t sweep_count) const {
|
||||||
assert_lock_strong(&_freelistLock);
|
assert_lock_strong(&_freelistLock);
|
||||||
FreeList<FreeChunk> total;
|
AdaptiveFreeList<FreeChunk> total;
|
||||||
gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count);
|
gclog_or_tty->print("end sweep# " SIZE_FORMAT "\n", sweep_count);
|
||||||
FreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||||
size_t total_free = 0;
|
size_t total_free = 0;
|
||||||
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
for (size_t i = IndexSetStart; i < IndexSetSize; i += IndexSetStride) {
|
||||||
const FreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
const AdaptiveFreeList<FreeChunk> *fl = &_indexedFreeList[i];
|
||||||
total_free += fl->count() * fl->size();
|
total_free += fl->count() * fl->size();
|
||||||
if (i % (40*IndexSetStride) == 0) {
|
if (i % (40*IndexSetStride) == 0) {
|
||||||
FreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
AdaptiveFreeList<FreeChunk>::print_labels_on(gclog_or_tty, "size");
|
||||||
}
|
}
|
||||||
fl->print_on(gclog_or_tty);
|
fl->print_on(gclog_or_tty);
|
||||||
total.set_bfr_surp( total.bfr_surp() + fl->bfr_surp() );
|
total.set_bfr_surp( total.bfr_surp() + fl->bfr_surp() );
|
||||||
|
@ -2620,7 +2622,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
||||||
res = _cfls->getChunkFromDictionaryExact(word_sz);
|
res = _cfls->getChunkFromDictionaryExact(word_sz);
|
||||||
if (res == NULL) return NULL;
|
if (res == NULL) return NULL;
|
||||||
} else {
|
} else {
|
||||||
FreeList<FreeChunk>* fl = &_indexedFreeList[word_sz];
|
AdaptiveFreeList<FreeChunk>* fl = &_indexedFreeList[word_sz];
|
||||||
if (fl->count() == 0) {
|
if (fl->count() == 0) {
|
||||||
// Attempt to refill this local free list.
|
// Attempt to refill this local free list.
|
||||||
get_from_global_pool(word_sz, fl);
|
get_from_global_pool(word_sz, fl);
|
||||||
|
@ -2640,7 +2642,7 @@ HeapWord* CFLS_LAB::alloc(size_t word_sz) {
|
||||||
|
|
||||||
// Get a chunk of blocks of the right size and update related
|
// Get a chunk of blocks of the right size and update related
|
||||||
// book-keeping stats
|
// book-keeping stats
|
||||||
void CFLS_LAB::get_from_global_pool(size_t word_sz, FreeList<FreeChunk>* fl) {
|
void CFLS_LAB::get_from_global_pool(size_t word_sz, AdaptiveFreeList<FreeChunk>* fl) {
|
||||||
// Get the #blocks we want to claim
|
// Get the #blocks we want to claim
|
||||||
size_t n_blks = (size_t)_blocks_to_claim[word_sz].average();
|
size_t n_blks = (size_t)_blocks_to_claim[word_sz].average();
|
||||||
assert(n_blks > 0, "Error");
|
assert(n_blks > 0, "Error");
|
||||||
|
@ -2722,7 +2724,7 @@ void CFLS_LAB::retire(int tid) {
|
||||||
if (num_retire > 0) {
|
if (num_retire > 0) {
|
||||||
_cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]);
|
_cfls->_indexedFreeList[i].prepend(&_indexedFreeList[i]);
|
||||||
// Reset this list.
|
// Reset this list.
|
||||||
_indexedFreeList[i] = FreeList<FreeChunk>();
|
_indexedFreeList[i] = AdaptiveFreeList<FreeChunk>();
|
||||||
_indexedFreeList[i].set_size(i);
|
_indexedFreeList[i].set_size(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2736,7 +2738,7 @@ void CFLS_LAB::retire(int tid) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList<FreeChunk>* fl) {
|
void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList<FreeChunk>* fl) {
|
||||||
assert(fl->count() == 0, "Precondition.");
|
assert(fl->count() == 0, "Precondition.");
|
||||||
assert(word_sz < CompactibleFreeListSpace::IndexSetSize,
|
assert(word_sz < CompactibleFreeListSpace::IndexSetSize,
|
||||||
"Precondition");
|
"Precondition");
|
||||||
|
@ -2752,12 +2754,12 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
||||||
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
|
(cur_sz < CompactibleFreeListSpace::IndexSetSize) &&
|
||||||
(CMSSplitIndexedFreeListBlocks || k <= 1);
|
(CMSSplitIndexedFreeListBlocks || k <= 1);
|
||||||
k++, cur_sz = k * word_sz) {
|
k++, cur_sz = k * word_sz) {
|
||||||
FreeList<FreeChunk> fl_for_cur_sz; // Empty.
|
AdaptiveFreeList<FreeChunk> fl_for_cur_sz; // Empty.
|
||||||
fl_for_cur_sz.set_size(cur_sz);
|
fl_for_cur_sz.set_size(cur_sz);
|
||||||
{
|
{
|
||||||
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
|
MutexLockerEx x(_indexedFreeListParLocks[cur_sz],
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
FreeList<FreeChunk>* gfl = &_indexedFreeList[cur_sz];
|
AdaptiveFreeList<FreeChunk>* gfl = &_indexedFreeList[cur_sz];
|
||||||
if (gfl->count() != 0) {
|
if (gfl->count() != 0) {
|
||||||
// nn is the number of chunks of size cur_sz that
|
// nn is the number of chunks of size cur_sz that
|
||||||
// we'd need to split k-ways each, in order to create
|
// we'd need to split k-ways each, in order to create
|
||||||
|
@ -2832,12 +2834,11 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
||||||
MutexLockerEx x(parDictionaryAllocLock(),
|
MutexLockerEx x(parDictionaryAllocLock(),
|
||||||
Mutex::_no_safepoint_check_flag);
|
Mutex::_no_safepoint_check_flag);
|
||||||
while (n > 0) {
|
while (n > 0) {
|
||||||
fc = dictionary()->get_chunk(MAX2(n * word_sz,
|
fc = dictionary()->get_chunk(MAX2(n * word_sz, _dictionary->min_size()),
|
||||||
_dictionary->min_size()),
|
|
||||||
FreeBlockDictionary<FreeChunk>::atLeast);
|
FreeBlockDictionary<FreeChunk>::atLeast);
|
||||||
if (fc != NULL) {
|
if (fc != NULL) {
|
||||||
_bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk
|
_bt.allocated((HeapWord*)fc, fc->size(), true /* reducing */); // update _unallocated_blk
|
||||||
dictionary()->dict_census_udpate(fc->size(),
|
dictionary()->dict_census_update(fc->size(),
|
||||||
true /*split*/,
|
true /*split*/,
|
||||||
false /*birth*/);
|
false /*birth*/);
|
||||||
break;
|
break;
|
||||||
|
@ -2890,7 +2891,7 @@ void CompactibleFreeListSpace:: par_get_chunk_of_blocks(size_t word_sz, size_t n
|
||||||
fc->set_size(prefix_size);
|
fc->set_size(prefix_size);
|
||||||
if (rem >= IndexSetSize) {
|
if (rem >= IndexSetSize) {
|
||||||
returnChunkToDictionary(rem_fc);
|
returnChunkToDictionary(rem_fc);
|
||||||
dictionary()->dict_census_udpate(rem, true /*split*/, true /*birth*/);
|
dictionary()->dict_census_update(rem, true /*split*/, true /*birth*/);
|
||||||
rem_fc = NULL;
|
rem_fc = NULL;
|
||||||
}
|
}
|
||||||
// Otherwise, return it to the small list below.
|
// Otherwise, return it to the small list below.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
||||||
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_COMPACTIBLEFREELISTSPACE_HPP
|
||||||
|
|
||||||
|
#include "gc_implementation/concurrentMarkSweep/adaptiveFreeList.hpp"
|
||||||
#include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp"
|
#include "gc_implementation/concurrentMarkSweep/promotionInfo.hpp"
|
||||||
#include "memory/binaryTreeDictionary.hpp"
|
#include "memory/binaryTreeDictionary.hpp"
|
||||||
#include "memory/blockOffsetTable.inline.hpp"
|
#include "memory/blockOffsetTable.inline.hpp"
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
class CompactibleFreeListSpace;
|
class CompactibleFreeListSpace;
|
||||||
class BlkClosure;
|
class BlkClosure;
|
||||||
class BlkClosureCareful;
|
class BlkClosureCareful;
|
||||||
|
class FreeChunk;
|
||||||
class UpwardsObjectClosure;
|
class UpwardsObjectClosure;
|
||||||
class ObjectClosureCareful;
|
class ObjectClosureCareful;
|
||||||
class Klass;
|
class Klass;
|
||||||
|
@ -131,7 +133,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||||
FreeBlockDictionary<FreeChunk>::DictionaryChoice _dictionaryChoice;
|
FreeBlockDictionary<FreeChunk>::DictionaryChoice _dictionaryChoice;
|
||||||
FreeBlockDictionary<FreeChunk>* _dictionary; // ptr to dictionary for large size blocks
|
FreeBlockDictionary<FreeChunk>* _dictionary; // ptr to dictionary for large size blocks
|
||||||
|
|
||||||
FreeList<FreeChunk> _indexedFreeList[IndexSetSize];
|
AdaptiveFreeList<FreeChunk> _indexedFreeList[IndexSetSize];
|
||||||
// indexed array for small size blocks
|
// indexed array for small size blocks
|
||||||
// allocation stategy
|
// allocation stategy
|
||||||
bool _fitStrategy; // Use best fit strategy.
|
bool _fitStrategy; // Use best fit strategy.
|
||||||
|
@ -168,7 +170,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||||
// If the count of "fl" is negative, it's absolute value indicates a
|
// If the count of "fl" is negative, it's absolute value indicates a
|
||||||
// number of free chunks that had been previously "borrowed" from global
|
// number of free chunks that had been previously "borrowed" from global
|
||||||
// list of size "word_sz", and must now be decremented.
|
// list of size "word_sz", and must now be decremented.
|
||||||
void par_get_chunk_of_blocks(size_t word_sz, size_t n, FreeList<FreeChunk>* fl);
|
void par_get_chunk_of_blocks(size_t word_sz, size_t n, AdaptiveFreeList<FreeChunk>* fl);
|
||||||
|
|
||||||
// Allocation helper functions
|
// Allocation helper functions
|
||||||
// Allocate using a strategy that takes from the indexed free lists
|
// Allocate using a strategy that takes from the indexed free lists
|
||||||
|
@ -214,7 +216,7 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||||
// and return it. The split off remainder is returned to
|
// and return it. The split off remainder is returned to
|
||||||
// the free lists. The old name for getFromListGreater
|
// the free lists. The old name for getFromListGreater
|
||||||
// was lookInListGreater.
|
// was lookInListGreater.
|
||||||
FreeChunk* getFromListGreater(FreeList<FreeChunk>* fl, size_t numWords);
|
FreeChunk* getFromListGreater(AdaptiveFreeList<FreeChunk>* fl, size_t numWords);
|
||||||
// Get a chunk in the indexed free list or dictionary,
|
// Get a chunk in the indexed free list or dictionary,
|
||||||
// by considering a larger chunk and splitting it.
|
// by considering a larger chunk and splitting it.
|
||||||
FreeChunk* getChunkFromGreater(size_t numWords);
|
FreeChunk* getChunkFromGreater(size_t numWords);
|
||||||
|
@ -621,7 +623,7 @@ class CFLS_LAB : public CHeapObj<mtGC> {
|
||||||
CompactibleFreeListSpace* _cfls;
|
CompactibleFreeListSpace* _cfls;
|
||||||
|
|
||||||
// Our local free lists.
|
// Our local free lists.
|
||||||
FreeList<FreeChunk> _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
|
AdaptiveFreeList<FreeChunk> _indexedFreeList[CompactibleFreeListSpace::IndexSetSize];
|
||||||
|
|
||||||
// Initialized from a command-line arg.
|
// Initialized from a command-line arg.
|
||||||
|
|
||||||
|
@ -634,7 +636,7 @@ class CFLS_LAB : public CHeapObj<mtGC> {
|
||||||
size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize];
|
size_t _num_blocks [CompactibleFreeListSpace::IndexSetSize];
|
||||||
|
|
||||||
// Internal work method
|
// Internal work method
|
||||||
void get_from_global_pool(size_t word_sz, FreeList<FreeChunk>* fl);
|
void get_from_global_pool(size_t word_sz, AdaptiveFreeList<FreeChunk>* fl);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
CFLS_LAB(CompactibleFreeListSpace* cfls);
|
CFLS_LAB(CompactibleFreeListSpace* cfls);
|
||||||
|
|
|
@ -9143,7 +9143,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) {
|
||||||
size_t shrinkable_size_in_bytes = chunk_at_end->size();
|
size_t shrinkable_size_in_bytes = chunk_at_end->size();
|
||||||
size_t aligned_shrinkable_size_in_bytes =
|
size_t aligned_shrinkable_size_in_bytes =
|
||||||
align_size_down(shrinkable_size_in_bytes, os::vm_page_size());
|
align_size_down(shrinkable_size_in_bytes, os::vm_page_size());
|
||||||
assert(unallocated_start <= chunk_at_end->end(),
|
assert(unallocated_start <= (HeapWord*) chunk_at_end->end(),
|
||||||
"Inconsistent chunk at end of space");
|
"Inconsistent chunk at end of space");
|
||||||
size_t bytes = MIN2(desired_bytes, aligned_shrinkable_size_in_bytes);
|
size_t bytes = MIN2(desired_bytes, aligned_shrinkable_size_in_bytes);
|
||||||
size_t word_size_before = heap_word_size(_virtual_space.committed_size());
|
size_t word_size_before = heap_word_size(_virtual_space.committed_size());
|
||||||
|
@ -9210,7 +9210,7 @@ void ASConcurrentMarkSweepGeneration::shrink_by(size_t desired_bytes) {
|
||||||
|
|
||||||
assert(_cmsSpace->unallocated_block() <= _cmsSpace->end(),
|
assert(_cmsSpace->unallocated_block() <= _cmsSpace->end(),
|
||||||
"Inconsistency at end of space");
|
"Inconsistency at end of space");
|
||||||
assert(chunk_at_end->end() == _cmsSpace->end(),
|
assert(chunk_at_end->end() == (uintptr_t*) _cmsSpace->end(),
|
||||||
"Shrinking is inconsistent");
|
"Shrinking is inconsistent");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
|
@ -133,7 +133,7 @@ class FreeChunk VALUE_OBJ_CLASS_SPEC {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Return the address past the end of this chunk
|
// Return the address past the end of this chunk
|
||||||
HeapWord* end() const { return ((HeapWord*) this) + size(); }
|
uintptr_t* end() const { return ((uintptr_t*) this) + size(); }
|
||||||
|
|
||||||
// debugging
|
// debugging
|
||||||
void verify() const PRODUCT_RETURN;
|
void verify() const PRODUCT_RETURN;
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
#ifndef SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
||||||
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
#define SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_VMSTRUCTS_CMS_HPP
|
||||||
|
|
||||||
|
typedef BinaryTreeDictionary<FreeChunk, AdaptiveFreeList> AFLBinaryTreeDictionary;
|
||||||
|
|
||||||
#define VM_STRUCTS_CMS(nonstatic_field, \
|
#define VM_STRUCTS_CMS(nonstatic_field, \
|
||||||
volatile_nonstatic_field, \
|
volatile_nonstatic_field, \
|
||||||
static_field) \
|
static_field) \
|
||||||
|
@ -38,14 +40,8 @@
|
||||||
nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \
|
nonstatic_field(CMSCollector, _markBitMap, CMSBitMap) \
|
||||||
nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \
|
nonstatic_field(ConcurrentMarkSweepGeneration, _cmsSpace, CompactibleFreeListSpace*) \
|
||||||
static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \
|
static_field(ConcurrentMarkSweepThread, _collector, CMSCollector*) \
|
||||||
volatile_nonstatic_field(FreeChunk, _size, size_t) \
|
|
||||||
nonstatic_field(FreeChunk, _next, FreeChunk*) \
|
|
||||||
nonstatic_field(FreeChunk, _prev, FreeChunk*) \
|
|
||||||
nonstatic_field(LinearAllocBlock, _word_size, size_t) \
|
nonstatic_field(LinearAllocBlock, _word_size, size_t) \
|
||||||
nonstatic_field(FreeList<FreeChunk>, _size, size_t) \
|
nonstatic_field(AFLBinaryTreeDictionary, _total_size, size_t) \
|
||||||
nonstatic_field(FreeList<FreeChunk>, _count, ssize_t) \
|
|
||||||
nonstatic_field(BinaryTreeDictionary<FreeChunk>,_total_size, size_t) \
|
|
||||||
nonstatic_field(CompactibleFreeListSpace, _dictionary, FreeBlockDictionary<FreeChunk>*) \
|
|
||||||
nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList<FreeChunk>) \
|
nonstatic_field(CompactibleFreeListSpace, _indexedFreeList[0], FreeList<FreeChunk>) \
|
||||||
nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock)
|
nonstatic_field(CompactibleFreeListSpace, _smallLinearAllocBlock, LinearAllocBlock)
|
||||||
|
|
||||||
|
@ -60,19 +56,17 @@
|
||||||
declare_toplevel_type(CMSCollector) \
|
declare_toplevel_type(CMSCollector) \
|
||||||
declare_toplevel_type(CMSBitMap) \
|
declare_toplevel_type(CMSBitMap) \
|
||||||
declare_toplevel_type(FreeChunk) \
|
declare_toplevel_type(FreeChunk) \
|
||||||
|
declare_toplevel_type(Metablock) \
|
||||||
declare_toplevel_type(ConcurrentMarkSweepThread*) \
|
declare_toplevel_type(ConcurrentMarkSweepThread*) \
|
||||||
declare_toplevel_type(ConcurrentMarkSweepGeneration*) \
|
declare_toplevel_type(ConcurrentMarkSweepGeneration*) \
|
||||||
declare_toplevel_type(SurrogateLockerThread*) \
|
declare_toplevel_type(SurrogateLockerThread*) \
|
||||||
declare_toplevel_type(CompactibleFreeListSpace*) \
|
declare_toplevel_type(CompactibleFreeListSpace*) \
|
||||||
declare_toplevel_type(CMSCollector*) \
|
declare_toplevel_type(CMSCollector*) \
|
||||||
declare_toplevel_type(FreeChunk*) \
|
declare_toplevel_type(AFLBinaryTreeDictionary*) \
|
||||||
declare_toplevel_type(BinaryTreeDictionary<FreeChunk>*) \
|
|
||||||
declare_toplevel_type(FreeBlockDictionary<FreeChunk>*) \
|
|
||||||
declare_toplevel_type(FreeList<FreeChunk>*) \
|
|
||||||
declare_toplevel_type(FreeList<FreeChunk>) \
|
|
||||||
declare_toplevel_type(LinearAllocBlock) \
|
declare_toplevel_type(LinearAllocBlock) \
|
||||||
declare_toplevel_type(FreeBlockDictionary<FreeChunk>) \
|
declare_toplevel_type(FreeBlockDictionary<FreeChunk>) \
|
||||||
declare_type(BinaryTreeDictionary<FreeChunk>, FreeBlockDictionary<FreeChunk>)
|
declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary<FreeChunk>) \
|
||||||
|
declare_type(AFLBinaryTreeDictionary, FreeBlockDictionary<FreeChunk>) \
|
||||||
|
|
||||||
#define VM_INT_CONSTANTS_CMS(declare_constant) \
|
#define VM_INT_CONSTANTS_CMS(declare_constant) \
|
||||||
declare_constant(Generation::ConcurrentMarkSweep) \
|
declare_constant(Generation::ConcurrentMarkSweep) \
|
||||||
|
|
|
@ -191,7 +191,7 @@ class VM_GenCollectFull: public VM_GC_Operation {
|
||||||
class VM_CollectForMetadataAllocation: public VM_GC_Operation {
|
class VM_CollectForMetadataAllocation: public VM_GC_Operation {
|
||||||
private:
|
private:
|
||||||
MetaWord* _result;
|
MetaWord* _result;
|
||||||
size_t _size; // size of object to be allocated
|
size_t _size; // size of object to be allocated
|
||||||
Metaspace::MetadataType _mdtype;
|
Metaspace::MetadataType _mdtype;
|
||||||
ClassLoaderData* _loader_data;
|
ClassLoaderData* _loader_data;
|
||||||
public:
|
public:
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -37,77 +37,78 @@
|
||||||
// A TreeList is a FreeList which can be used to maintain a
|
// A TreeList is a FreeList which can be used to maintain a
|
||||||
// binary tree of free lists.
|
// binary tree of free lists.
|
||||||
|
|
||||||
template <class Chunk> class TreeChunk;
|
template <class Chunk_t, template <class> class FreeList_t> class TreeChunk;
|
||||||
template <class Chunk> class BinaryTreeDictionary;
|
template <class Chunk_t, template <class> class FreeList_t> class BinaryTreeDictionary;
|
||||||
template <class Chunk> class AscendTreeCensusClosure;
|
template <class Chunk_t, template <class> class FreeList_t> class AscendTreeCensusClosure;
|
||||||
template <class Chunk> class DescendTreeCensusClosure;
|
template <class Chunk_t, template <class> class FreeList_t> class DescendTreeCensusClosure;
|
||||||
template <class Chunk> class DescendTreeSearchClosure;
|
template <class Chunk_t, template <class> class FreeList_t> class DescendTreeSearchClosure;
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk_t, template <class> class FreeList_t>
|
||||||
class TreeList: public FreeList<Chunk> {
|
class TreeList : public FreeList_t<Chunk_t> {
|
||||||
friend class TreeChunk<Chunk>;
|
friend class TreeChunk<Chunk_t, FreeList_t>;
|
||||||
friend class BinaryTreeDictionary<Chunk>;
|
friend class BinaryTreeDictionary<Chunk_t, FreeList_t>;
|
||||||
friend class AscendTreeCensusClosure<Chunk>;
|
friend class AscendTreeCensusClosure<Chunk_t, FreeList_t>;
|
||||||
friend class DescendTreeCensusClosure<Chunk>;
|
friend class DescendTreeCensusClosure<Chunk_t, FreeList_t>;
|
||||||
friend class DescendTreeSearchClosure<Chunk>;
|
friend class DescendTreeSearchClosure<Chunk_t, FreeList_t>;
|
||||||
|
|
||||||
TreeList<Chunk>* _parent;
|
TreeList<Chunk_t, FreeList_t>* _parent;
|
||||||
TreeList<Chunk>* _left;
|
TreeList<Chunk_t, FreeList_t>* _left;
|
||||||
TreeList<Chunk>* _right;
|
TreeList<Chunk_t, FreeList_t>* _right;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TreeList<Chunk>* parent() const { return _parent; }
|
|
||||||
TreeList<Chunk>* left() const { return _left; }
|
|
||||||
TreeList<Chunk>* right() const { return _right; }
|
|
||||||
|
|
||||||
// Explicitly import these names into our namespace to fix name lookup with templates
|
TreeList<Chunk_t, FreeList_t>* parent() const { return _parent; }
|
||||||
using FreeList<Chunk>::head;
|
TreeList<Chunk_t, FreeList_t>* left() const { return _left; }
|
||||||
using FreeList<Chunk>::set_head;
|
TreeList<Chunk_t, FreeList_t>* right() const { return _right; }
|
||||||
|
|
||||||
using FreeList<Chunk>::tail;
|
// Wrapper on call to base class, to get the template to compile.
|
||||||
using FreeList<Chunk>::set_tail;
|
Chunk_t* head() const { return FreeList_t<Chunk_t>::head(); }
|
||||||
using FreeList<Chunk>::link_tail;
|
Chunk_t* tail() const { return FreeList_t<Chunk_t>::tail(); }
|
||||||
|
void set_head(Chunk_t* head) { FreeList_t<Chunk_t>::set_head(head); }
|
||||||
|
void set_tail(Chunk_t* tail) { FreeList_t<Chunk_t>::set_tail(tail); }
|
||||||
|
|
||||||
using FreeList<Chunk>::increment_count;
|
size_t size() const { return FreeList_t<Chunk_t>::size(); }
|
||||||
NOT_PRODUCT(using FreeList<Chunk>::increment_returned_bytes_by;)
|
|
||||||
using FreeList<Chunk>::verify_chunk_in_free_list;
|
|
||||||
using FreeList<Chunk>::size;
|
|
||||||
|
|
||||||
// Accessors for links in tree.
|
// Accessors for links in tree.
|
||||||
|
|
||||||
void set_left(TreeList<Chunk>* tl) {
|
void set_left(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||||
_left = tl;
|
_left = tl;
|
||||||
if (tl != NULL)
|
if (tl != NULL)
|
||||||
tl->set_parent(this);
|
tl->set_parent(this);
|
||||||
}
|
}
|
||||||
void set_right(TreeList<Chunk>* tl) {
|
void set_right(TreeList<Chunk_t, FreeList_t>* tl) {
|
||||||
_right = tl;
|
_right = tl;
|
||||||
if (tl != NULL)
|
if (tl != NULL)
|
||||||
tl->set_parent(this);
|
tl->set_parent(this);
|
||||||
}
|
}
|
||||||
void set_parent(TreeList<Chunk>* tl) { _parent = tl; }
|
void set_parent(TreeList<Chunk_t, FreeList_t>* tl) { _parent = tl; }
|
||||||
|
|
||||||
void clearLeft() { _left = NULL; }
|
void clear_left() { _left = NULL; }
|
||||||
void clear_right() { _right = NULL; }
|
void clear_right() { _right = NULL; }
|
||||||
void clear_parent() { _parent = NULL; }
|
void clear_parent() { _parent = NULL; }
|
||||||
void initialize() { clearLeft(); clear_right(), clear_parent(); }
|
void initialize() { clear_left(); clear_right(), clear_parent(); FreeList_t<Chunk_t>::initialize(); }
|
||||||
|
|
||||||
// For constructing a TreeList from a Tree chunk or
|
// For constructing a TreeList from a Tree chunk or
|
||||||
// address and size.
|
// address and size.
|
||||||
static TreeList<Chunk>* as_TreeList(TreeChunk<Chunk>* tc);
|
TreeList();
|
||||||
static TreeList<Chunk>* as_TreeList(HeapWord* addr, size_t size);
|
static TreeList<Chunk_t, FreeList_t>*
|
||||||
|
as_TreeList(TreeChunk<Chunk_t, FreeList_t>* tc);
|
||||||
|
static TreeList<Chunk_t, FreeList_t>* as_TreeList(HeapWord* addr, size_t size);
|
||||||
|
|
||||||
// Returns the head of the free list as a pointer to a TreeChunk.
|
// Returns the head of the free list as a pointer to a TreeChunk.
|
||||||
TreeChunk<Chunk>* head_as_TreeChunk();
|
TreeChunk<Chunk_t, FreeList_t>* head_as_TreeChunk();
|
||||||
|
|
||||||
// Returns the first available chunk in the free list as a pointer
|
// Returns the first available chunk in the free list as a pointer
|
||||||
// to a TreeChunk.
|
// to a TreeChunk.
|
||||||
TreeChunk<Chunk>* first_available();
|
TreeChunk<Chunk_t, FreeList_t>* first_available();
|
||||||
|
|
||||||
// Returns the block with the largest heap address amongst
|
// Returns the block with the largest heap address amongst
|
||||||
// those in the list for this size; potentially slow and expensive,
|
// those in the list for this size; potentially slow and expensive,
|
||||||
// use with caution!
|
// use with caution!
|
||||||
TreeChunk<Chunk>* largest_address();
|
TreeChunk<Chunk_t, FreeList_t>* largest_address();
|
||||||
|
|
||||||
|
TreeList<Chunk_t, FreeList_t>* get_better_list(
|
||||||
|
BinaryTreeDictionary<Chunk_t, FreeList_t>* dictionary);
|
||||||
|
|
||||||
// remove_chunk_replace_if_needed() removes the given "tc" from the TreeList.
|
// remove_chunk_replace_if_needed() removes the given "tc" from the TreeList.
|
||||||
// If "tc" is the first chunk in the list, it is also the
|
// If "tc" is the first chunk in the list, it is also the
|
||||||
|
@ -115,10 +116,10 @@ class TreeList: public FreeList<Chunk> {
|
||||||
// returns the possibly replaced TreeList* for the node in
|
// returns the possibly replaced TreeList* for the node in
|
||||||
// the tree. It also updates the parent of the original
|
// the tree. It also updates the parent of the original
|
||||||
// node to point to the new node.
|
// node to point to the new node.
|
||||||
TreeList<Chunk>* remove_chunk_replace_if_needed(TreeChunk<Chunk>* tc);
|
TreeList<Chunk_t, FreeList_t>* remove_chunk_replace_if_needed(TreeChunk<Chunk_t, FreeList_t>* tc);
|
||||||
// See FreeList.
|
// See FreeList.
|
||||||
void return_chunk_at_head(TreeChunk<Chunk>* tc);
|
void return_chunk_at_head(TreeChunk<Chunk_t, FreeList_t>* tc);
|
||||||
void return_chunk_at_tail(TreeChunk<Chunk>* tc);
|
void return_chunk_at_tail(TreeChunk<Chunk_t, FreeList_t>* tc);
|
||||||
};
|
};
|
||||||
|
|
||||||
// A TreeChunk is a subclass of a Chunk that additionally
|
// A TreeChunk is a subclass of a Chunk that additionally
|
||||||
|
@ -134,52 +135,54 @@ class TreeList: public FreeList<Chunk> {
|
||||||
// on the free list for a node in the tree and is only removed if
|
// on the free list for a node in the tree and is only removed if
|
||||||
// it is the last chunk on the free list.
|
// it is the last chunk on the free list.
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk_t, template <class> class FreeList_t>
|
||||||
class TreeChunk : public Chunk {
|
class TreeChunk : public Chunk_t {
|
||||||
friend class TreeList<Chunk>;
|
friend class TreeList<Chunk_t, FreeList_t>;
|
||||||
TreeList<Chunk>* _list;
|
TreeList<Chunk_t, FreeList_t>* _list;
|
||||||
TreeList<Chunk> _embedded_list; // if non-null, this chunk is on _list
|
TreeList<Chunk_t, FreeList_t> _embedded_list; // if non-null, this chunk is on _list
|
||||||
|
|
||||||
|
static size_t _min_tree_chunk_size;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
TreeList<Chunk>* embedded_list() const { return (TreeList<Chunk>*) &_embedded_list; }
|
TreeList<Chunk_t, FreeList_t>* embedded_list() const { return (TreeList<Chunk_t, FreeList_t>*) &_embedded_list; }
|
||||||
void set_embedded_list(TreeList<Chunk>* v) { _embedded_list = *v; }
|
void set_embedded_list(TreeList<Chunk_t, FreeList_t>* v) { _embedded_list = *v; }
|
||||||
public:
|
public:
|
||||||
TreeList<Chunk>* list() { return _list; }
|
TreeList<Chunk_t, FreeList_t>* list() { return _list; }
|
||||||
void set_list(TreeList<Chunk>* v) { _list = v; }
|
void set_list(TreeList<Chunk_t, FreeList_t>* v) { _list = v; }
|
||||||
static TreeChunk<Chunk>* as_TreeChunk(Chunk* fc);
|
static TreeChunk<Chunk_t, FreeList_t>* as_TreeChunk(Chunk_t* fc);
|
||||||
// Initialize fields in a TreeChunk that should be
|
// Initialize fields in a TreeChunk that should be
|
||||||
// initialized when the TreeChunk is being added to
|
// initialized when the TreeChunk is being added to
|
||||||
// a free list in the tree.
|
// a free list in the tree.
|
||||||
void initialize() { embedded_list()->initialize(); }
|
void initialize() { embedded_list()->initialize(); }
|
||||||
|
|
||||||
Chunk* next() const { return Chunk::next(); }
|
Chunk_t* next() const { return Chunk_t::next(); }
|
||||||
Chunk* prev() const { return Chunk::prev(); }
|
Chunk_t* prev() const { return Chunk_t::prev(); }
|
||||||
size_t size() const volatile { return Chunk::size(); }
|
size_t size() const volatile { return Chunk_t::size(); }
|
||||||
|
|
||||||
|
static size_t min_size() {
|
||||||
|
return _min_tree_chunk_size;
|
||||||
|
}
|
||||||
|
|
||||||
// debugging
|
// debugging
|
||||||
void verify_tree_chunk_list() const;
|
void verify_tree_chunk_list() const;
|
||||||
|
void assert_is_mangled() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk_t, template <class> class FreeList_t>
|
||||||
class BinaryTreeDictionary: public FreeBlockDictionary<Chunk> {
|
class BinaryTreeDictionary: public FreeBlockDictionary<Chunk_t> {
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
bool _splay;
|
|
||||||
bool _adaptive_freelists;
|
|
||||||
size_t _total_size;
|
size_t _total_size;
|
||||||
size_t _total_free_blocks;
|
size_t _total_free_blocks;
|
||||||
TreeList<Chunk>* _root;
|
TreeList<Chunk_t, FreeList_t>* _root;
|
||||||
|
|
||||||
// private accessors
|
// private accessors
|
||||||
bool splay() const { return _splay; }
|
|
||||||
void set_splay(bool v) { _splay = v; }
|
|
||||||
void set_total_size(size_t v) { _total_size = v; }
|
void set_total_size(size_t v) { _total_size = v; }
|
||||||
virtual void inc_total_size(size_t v);
|
virtual void inc_total_size(size_t v);
|
||||||
virtual void dec_total_size(size_t v);
|
virtual void dec_total_size(size_t v);
|
||||||
size_t total_free_blocks() const { return _total_free_blocks; }
|
|
||||||
void set_total_free_blocks(size_t v) { _total_free_blocks = v; }
|
void set_total_free_blocks(size_t v) { _total_free_blocks = v; }
|
||||||
TreeList<Chunk>* root() const { return _root; }
|
TreeList<Chunk_t, FreeList_t>* root() const { return _root; }
|
||||||
void set_root(TreeList<Chunk>* v) { _root = v; }
|
void set_root(TreeList<Chunk_t, FreeList_t>* v) { _root = v; }
|
||||||
bool adaptive_freelists() { return _adaptive_freelists; }
|
|
||||||
|
|
||||||
// This field is added and can be set to point to the
|
// This field is added and can be set to point to the
|
||||||
// the Mutex used to synchronize access to the
|
// the Mutex used to synchronize access to the
|
||||||
|
@ -191,54 +194,55 @@ class BinaryTreeDictionary: public FreeBlockDictionary<Chunk> {
|
||||||
// return it. If the chunk
|
// return it. If the chunk
|
||||||
// is the last chunk of that size, remove the node for that size
|
// is the last chunk of that size, remove the node for that size
|
||||||
// from the tree.
|
// from the tree.
|
||||||
TreeChunk<Chunk>* get_chunk_from_tree(size_t size, enum FreeBlockDictionary<Chunk>::Dither dither, bool splay);
|
TreeChunk<Chunk_t, FreeList_t>* get_chunk_from_tree(size_t size, enum FreeBlockDictionary<Chunk_t>::Dither dither);
|
||||||
// Return a list of the specified size or NULL from the tree.
|
|
||||||
// The list is not removed from the tree.
|
|
||||||
TreeList<Chunk>* find_list (size_t size) const;
|
|
||||||
// Remove this chunk from the tree. If the removal results
|
// Remove this chunk from the tree. If the removal results
|
||||||
// in an empty list in the tree, remove the empty list.
|
// in an empty list in the tree, remove the empty list.
|
||||||
TreeChunk<Chunk>* remove_chunk_from_tree(TreeChunk<Chunk>* tc);
|
TreeChunk<Chunk_t, FreeList_t>* remove_chunk_from_tree(TreeChunk<Chunk_t, FreeList_t>* tc);
|
||||||
// Remove the node in the trees starting at tl that has the
|
// Remove the node in the trees starting at tl that has the
|
||||||
// minimum value and return it. Repair the tree as needed.
|
// minimum value and return it. Repair the tree as needed.
|
||||||
TreeList<Chunk>* remove_tree_minimum(TreeList<Chunk>* tl);
|
TreeList<Chunk_t, FreeList_t>* remove_tree_minimum(TreeList<Chunk_t, FreeList_t>* tl);
|
||||||
void semi_splay_step(TreeList<Chunk>* tl);
|
|
||||||
// Add this free chunk to the tree.
|
// Add this free chunk to the tree.
|
||||||
void insert_chunk_in_tree(Chunk* freeChunk);
|
void insert_chunk_in_tree(Chunk_t* freeChunk);
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static const size_t min_tree_chunk_size = sizeof(TreeChunk<Chunk>)/HeapWordSize;
|
// Return a list of the specified size or NULL from the tree.
|
||||||
|
// The list is not removed from the tree.
|
||||||
|
TreeList<Chunk_t, FreeList_t>* find_list (size_t size) const;
|
||||||
|
|
||||||
void verify_tree() const;
|
void verify_tree() const;
|
||||||
// verify that the given chunk is in the tree.
|
// verify that the given chunk is in the tree.
|
||||||
bool verify_chunk_in_free_list(Chunk* tc) const;
|
bool verify_chunk_in_free_list(Chunk_t* tc) const;
|
||||||
private:
|
private:
|
||||||
void verify_tree_helper(TreeList<Chunk>* tl) const;
|
void verify_tree_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
static size_t verify_prev_free_ptrs(TreeList<Chunk>* tl);
|
static size_t verify_prev_free_ptrs(TreeList<Chunk_t, FreeList_t>* tl);
|
||||||
|
|
||||||
// Returns the total number of chunks in the list.
|
// Returns the total number of chunks in the list.
|
||||||
size_t total_list_length(TreeList<Chunk>* tl) const;
|
size_t total_list_length(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
// Returns the total number of words in the chunks in the tree
|
// Returns the total number of words in the chunks in the tree
|
||||||
// starting at "tl".
|
// starting at "tl".
|
||||||
size_t total_size_in_tree(TreeList<Chunk>* tl) const;
|
size_t total_size_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
// Returns the sum of the square of the size of each block
|
// Returns the sum of the square of the size of each block
|
||||||
// in the tree starting at "tl".
|
// in the tree starting at "tl".
|
||||||
double sum_of_squared_block_sizes(TreeList<Chunk>* const tl) const;
|
double sum_of_squared_block_sizes(TreeList<Chunk_t, FreeList_t>* const tl) const;
|
||||||
// Returns the total number of free blocks in the tree starting
|
// Returns the total number of free blocks in the tree starting
|
||||||
// at "tl".
|
// at "tl".
|
||||||
size_t total_free_blocks_in_tree(TreeList<Chunk>* tl) const;
|
size_t total_free_blocks_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
size_t num_free_blocks() const;
|
size_t num_free_blocks() const;
|
||||||
size_t treeHeight() const;
|
size_t tree_height() const;
|
||||||
size_t tree_height_helper(TreeList<Chunk>* tl) const;
|
size_t tree_height_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
size_t total_nodes_in_tree(TreeList<Chunk>* tl) const;
|
size_t total_nodes_in_tree(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
size_t total_nodes_helper(TreeList<Chunk>* tl) const;
|
size_t total_nodes_helper(TreeList<Chunk_t, FreeList_t>* tl) const;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
// Constructor
|
// Constructor
|
||||||
BinaryTreeDictionary(bool adaptive_freelists, bool splay = false);
|
BinaryTreeDictionary() :
|
||||||
BinaryTreeDictionary(MemRegion mr, bool adaptive_freelists, bool splay = false);
|
_total_size(0), _total_free_blocks(0), _root(0) {}
|
||||||
|
|
||||||
|
BinaryTreeDictionary(MemRegion mr);
|
||||||
|
|
||||||
// Public accessors
|
// Public accessors
|
||||||
size_t total_size() const { return _total_size; }
|
size_t total_size() const { return _total_size; }
|
||||||
|
size_t total_free_blocks() const { return _total_free_blocks; }
|
||||||
|
|
||||||
// Reset the dictionary to the initial conditions with
|
// Reset the dictionary to the initial conditions with
|
||||||
// a single free chunk.
|
// a single free chunk.
|
||||||
|
@ -249,23 +253,24 @@ class BinaryTreeDictionary: public FreeBlockDictionary<Chunk> {
|
||||||
|
|
||||||
// Return a chunk of size "size" or greater from
|
// Return a chunk of size "size" or greater from
|
||||||
// the tree.
|
// the tree.
|
||||||
// want a better dynamic splay strategy for the future.
|
Chunk_t* get_chunk(size_t size, enum FreeBlockDictionary<Chunk_t>::Dither dither) {
|
||||||
Chunk* get_chunk(size_t size, enum FreeBlockDictionary<Chunk>::Dither dither) {
|
FreeBlockDictionary<Chunk_t>::verify_par_locked();
|
||||||
FreeBlockDictionary<Chunk>::verify_par_locked();
|
Chunk_t* res = get_chunk_from_tree(size, dither);
|
||||||
Chunk* res = get_chunk_from_tree(size, dither, splay());
|
|
||||||
assert(res == NULL || res->is_free(),
|
assert(res == NULL || res->is_free(),
|
||||||
"Should be returning a free chunk");
|
"Should be returning a free chunk");
|
||||||
|
assert(dither != FreeBlockDictionary<Chunk_t>::exactly ||
|
||||||
|
res->size() == size, "Not correct size");
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
void return_chunk(Chunk* chunk) {
|
void return_chunk(Chunk_t* chunk) {
|
||||||
FreeBlockDictionary<Chunk>::verify_par_locked();
|
FreeBlockDictionary<Chunk_t>::verify_par_locked();
|
||||||
insert_chunk_in_tree(chunk);
|
insert_chunk_in_tree(chunk);
|
||||||
}
|
}
|
||||||
|
|
||||||
void remove_chunk(Chunk* chunk) {
|
void remove_chunk(Chunk_t* chunk) {
|
||||||
FreeBlockDictionary<Chunk>::verify_par_locked();
|
FreeBlockDictionary<Chunk_t>::verify_par_locked();
|
||||||
remove_chunk_from_tree((TreeChunk<Chunk>*)chunk);
|
remove_chunk_from_tree((TreeChunk<Chunk_t, FreeList_t>*)chunk);
|
||||||
assert(chunk->is_free(), "Should still be a free chunk");
|
assert(chunk->is_free(), "Should still be a free chunk");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,19 +286,19 @@ class BinaryTreeDictionary: public FreeBlockDictionary<Chunk> {
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t min_size() const {
|
size_t min_size() const {
|
||||||
return min_tree_chunk_size;
|
return TreeChunk<Chunk_t, FreeList_t>::min_size();
|
||||||
}
|
}
|
||||||
|
|
||||||
double sum_of_squared_block_sizes() const {
|
double sum_of_squared_block_sizes() const {
|
||||||
return sum_of_squared_block_sizes(root());
|
return sum_of_squared_block_sizes(root());
|
||||||
}
|
}
|
||||||
|
|
||||||
Chunk* find_chunk_ends_at(HeapWord* target) const;
|
Chunk_t* find_chunk_ends_at(HeapWord* target) const;
|
||||||
|
|
||||||
// Find the list with size "size" in the binary tree and update
|
// Find the list with size "size" in the binary tree and update
|
||||||
// the statistics in the list according to "split" (chunk was
|
// the statistics in the list according to "split" (chunk was
|
||||||
// split or coalesce) and "birth" (chunk was added or removed).
|
// split or coalesce) and "birth" (chunk was added or removed).
|
||||||
void dict_census_udpate(size_t size, bool split, bool birth);
|
void dict_census_update(size_t size, bool split, bool birth);
|
||||||
// Return true if the dictionary is overpopulated (more chunks of
|
// Return true if the dictionary is overpopulated (more chunks of
|
||||||
// this size than desired) for size "size".
|
// this size than desired) for size "size".
|
||||||
bool coal_dict_over_populated(size_t size);
|
bool coal_dict_over_populated(size_t size);
|
||||||
|
@ -307,7 +312,7 @@ class BinaryTreeDictionary: public FreeBlockDictionary<Chunk> {
|
||||||
// statistics for the sweep.
|
// statistics for the sweep.
|
||||||
void end_sweep_dict_census(double splitSurplusPercent);
|
void end_sweep_dict_census(double splitSurplusPercent);
|
||||||
// Return the largest free chunk in the tree.
|
// Return the largest free chunk in the tree.
|
||||||
Chunk* find_largest_dict() const;
|
Chunk_t* find_largest_dict() const;
|
||||||
// Accessors for statistics
|
// Accessors for statistics
|
||||||
void set_tree_surplus(double splitSurplusPercent);
|
void set_tree_surplus(double splitSurplusPercent);
|
||||||
void set_tree_hints(void);
|
void set_tree_hints(void);
|
||||||
|
|
|
@ -27,6 +27,8 @@
|
||||||
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
#include "gc_implementation/concurrentMarkSweep/freeChunk.hpp"
|
||||||
#endif // SERIALGC
|
#endif // SERIALGC
|
||||||
#include "memory/freeBlockDictionary.hpp"
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
|
#include "memory/metablock.hpp"
|
||||||
|
#include "memory/metachunk.hpp"
|
||||||
#ifdef TARGET_OS_FAMILY_linux
|
#ifdef TARGET_OS_FAMILY_linux
|
||||||
# include "thread_linux.inline.hpp"
|
# include "thread_linux.inline.hpp"
|
||||||
#endif
|
#endif
|
||||||
|
@ -62,6 +64,9 @@ template <class Chunk> void FreeBlockDictionary<Chunk>::verify_par_locked() cons
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
template class FreeBlockDictionary<Metablock>;
|
||||||
|
template class FreeBlockDictionary<Metachunk>;
|
||||||
|
|
||||||
#ifndef SERIALGC
|
#ifndef SERIALGC
|
||||||
// Explicitly instantiate for FreeChunk
|
// Explicitly instantiate for FreeChunk
|
||||||
template class FreeBlockDictionary<FreeChunk>;
|
template class FreeBlockDictionary<FreeChunk>;
|
||||||
|
|
|
@ -66,7 +66,7 @@ class FreeBlockDictionary: public CHeapObj<mtGC> {
|
||||||
virtual void reset(HeapWord* addr, size_t size) = 0;
|
virtual void reset(HeapWord* addr, size_t size) = 0;
|
||||||
virtual void reset() = 0;
|
virtual void reset() = 0;
|
||||||
|
|
||||||
virtual void dict_census_udpate(size_t size, bool split, bool birth) = 0;
|
virtual void dict_census_update(size_t size, bool split, bool birth) = 0;
|
||||||
virtual bool coal_dict_over_populated(size_t size) = 0;
|
virtual bool coal_dict_over_populated(size_t size) = 0;
|
||||||
virtual void begin_sweep_dict_census(double coalSurplusPercent,
|
virtual void begin_sweep_dict_census(double coalSurplusPercent,
|
||||||
float inter_sweep_current, float inter_sweep_estimate,
|
float inter_sweep_current, float inter_sweep_estimate,
|
||||||
|
|
|
@ -25,6 +25,8 @@
|
||||||
#include "precompiled.hpp"
|
#include "precompiled.hpp"
|
||||||
#include "memory/freeBlockDictionary.hpp"
|
#include "memory/freeBlockDictionary.hpp"
|
||||||
#include "memory/freeList.hpp"
|
#include "memory/freeList.hpp"
|
||||||
|
#include "memory/metablock.hpp"
|
||||||
|
#include "memory/metachunk.hpp"
|
||||||
#include "memory/sharedHeap.hpp"
|
#include "memory/sharedHeap.hpp"
|
||||||
#include "runtime/globals.hpp"
|
#include "runtime/globals.hpp"
|
||||||
#include "runtime/mutex.hpp"
|
#include "runtime/mutex.hpp"
|
||||||
|
@ -49,8 +51,6 @@ FreeList<Chunk>::FreeList() :
|
||||||
{
|
{
|
||||||
_size = 0;
|
_size = 0;
|
||||||
_count = 0;
|
_count = 0;
|
||||||
_hint = 0;
|
|
||||||
init_statistics();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk>
|
||||||
|
@ -62,34 +62,50 @@ FreeList<Chunk>::FreeList(Chunk* fc) :
|
||||||
{
|
{
|
||||||
_size = fc->size();
|
_size = fc->size();
|
||||||
_count = 1;
|
_count = 1;
|
||||||
_hint = 0;
|
|
||||||
init_statistics();
|
|
||||||
#ifndef PRODUCT
|
|
||||||
_allocation_stats.set_returned_bytes(size() * HeapWordSize);
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk>
|
||||||
void FreeList<Chunk>::reset(size_t hint) {
|
void FreeList<Chunk>::link_head(Chunk* v) {
|
||||||
|
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) {
|
||||||
|
v->link_prev(NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
template <class Chunk>
|
||||||
|
void FreeList<Chunk>::reset() {
|
||||||
|
// Don't set the _size to 0 because this method is
|
||||||
|
// used with a existing list that has a size but which has
|
||||||
|
// been emptied.
|
||||||
|
// Don't clear the _protecting_lock of an existing list.
|
||||||
set_count(0);
|
set_count(0);
|
||||||
set_head(NULL);
|
set_head(NULL);
|
||||||
set_tail(NULL);
|
set_tail(NULL);
|
||||||
set_hint(hint);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk>
|
||||||
void FreeList<Chunk>::init_statistics(bool split_birth) {
|
void FreeList<Chunk>::initialize() {
|
||||||
_allocation_stats.initialize(split_birth);
|
#ifdef ASSERT
|
||||||
|
// Needed early because it might be checked in other initializing code.
|
||||||
|
set_protecting_lock(NULL);
|
||||||
|
#endif
|
||||||
|
reset();
|
||||||
|
set_size(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk_t>
|
||||||
Chunk* FreeList<Chunk>::get_chunk_at_head() {
|
Chunk_t* FreeList<Chunk_t>::get_chunk_at_head() {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
||||||
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
||||||
Chunk* fc = head();
|
Chunk_t* fc = head();
|
||||||
if (fc != NULL) {
|
if (fc != NULL) {
|
||||||
Chunk* nextFC = fc->next();
|
Chunk_t* nextFC = fc->next();
|
||||||
if (nextFC != NULL) {
|
if (nextFC != NULL) {
|
||||||
// The chunk fc being removed has a "next". Set the "next" to the
|
// The chunk fc being removed has a "next". Set the "next" to the
|
||||||
// "prev" of fc.
|
// "prev" of fc.
|
||||||
|
@ -197,11 +213,6 @@ void FreeList<Chunk>::return_chunk_at_head(Chunk* chunk, bool record_return) {
|
||||||
link_tail(chunk);
|
link_tail(chunk);
|
||||||
}
|
}
|
||||||
increment_count(); // of # of chunks in list
|
increment_count(); // of # of chunks in list
|
||||||
DEBUG_ONLY(
|
|
||||||
if (record_return) {
|
|
||||||
increment_returned_bytes_by(size()*HeapWordSize);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
||||||
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
||||||
assert(head() == NULL || head()->size() == size(), "wrong item on list");
|
assert(head() == NULL || head()->size() == size(), "wrong item on list");
|
||||||
|
@ -233,11 +244,6 @@ void FreeList<Chunk>::return_chunk_at_tail(Chunk* chunk, bool record_return) {
|
||||||
}
|
}
|
||||||
link_tail(chunk);
|
link_tail(chunk);
|
||||||
increment_count(); // of # of chunks in list
|
increment_count(); // of # of chunks in list
|
||||||
DEBUG_ONLY(
|
|
||||||
if (record_return) {
|
|
||||||
increment_returned_bytes_by(size()*HeapWordSize);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
assert(head() == NULL || head()->prev() == NULL, "list invariant");
|
||||||
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
assert(tail() == NULL || tail()->next() == NULL, "list invariant");
|
||||||
assert(head() == NULL || head()->size() == size(), "wrong item on list");
|
assert(head() == NULL || head()->size() == size(), "wrong item on list");
|
||||||
|
@ -273,7 +279,7 @@ void FreeList<Chunk>::prepend(FreeList<Chunk>* fl) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// verify_chunk_in_free_list() is used to verify that an item is in this free list.
|
// verify_chunk_in_free_lists() is used to verify that an item is in this free list.
|
||||||
// It is used as a debugging aid.
|
// It is used as a debugging aid.
|
||||||
template <class Chunk>
|
template <class Chunk>
|
||||||
bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
|
bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
|
||||||
|
@ -293,41 +299,15 @@ bool FreeList<Chunk>::verify_chunk_in_free_list(Chunk* fc) const {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifndef PRODUCT
|
#ifndef PRODUCT
|
||||||
template <class Chunk>
|
|
||||||
void FreeList<Chunk>::verify_stats() const {
|
|
||||||
// The +1 of the LH comparand is to allow some "looseness" in
|
|
||||||
// checking: we usually call this interface when adding a block
|
|
||||||
// and we'll subsequently update the stats; we cannot update the
|
|
||||||
// stats beforehand because in the case of the large-block BT
|
|
||||||
// dictionary for example, this might be the first block and
|
|
||||||
// in that case there would be no place that we could record
|
|
||||||
// the stats (which are kept in the block itself).
|
|
||||||
assert((_allocation_stats.prev_sweep() + _allocation_stats.split_births()
|
|
||||||
+ _allocation_stats.coal_births() + 1) // Total Production Stock + 1
|
|
||||||
>= (_allocation_stats.split_deaths() + _allocation_stats.coal_deaths()
|
|
||||||
+ (ssize_t)count()), // Total Current Stock + depletion
|
|
||||||
err_msg("FreeList " PTR_FORMAT " of size " SIZE_FORMAT
|
|
||||||
" violates Conservation Principle: "
|
|
||||||
"prev_sweep(" SIZE_FORMAT ")"
|
|
||||||
" + split_births(" SIZE_FORMAT ")"
|
|
||||||
" + coal_births(" SIZE_FORMAT ") + 1 >= "
|
|
||||||
" split_deaths(" SIZE_FORMAT ")"
|
|
||||||
" coal_deaths(" SIZE_FORMAT ")"
|
|
||||||
" + count(" SSIZE_FORMAT ")",
|
|
||||||
this, _size, _allocation_stats.prev_sweep(), _allocation_stats.split_births(),
|
|
||||||
_allocation_stats.split_births(), _allocation_stats.split_deaths(),
|
|
||||||
_allocation_stats.coal_deaths(), count()));
|
|
||||||
}
|
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk>
|
||||||
void FreeList<Chunk>::assert_proper_lock_protection_work() const {
|
void FreeList<Chunk>::assert_proper_lock_protection_work() const {
|
||||||
assert(_protecting_lock != NULL, "Don't call this directly");
|
assert(protecting_lock() != NULL, "Don't call this directly");
|
||||||
assert(ParallelGCThreads > 0, "Don't call this directly");
|
assert(ParallelGCThreads > 0, "Don't call this directly");
|
||||||
Thread* thr = Thread::current();
|
Thread* thr = Thread::current();
|
||||||
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
|
if (thr->is_VM_thread() || thr->is_ConcurrentGC_thread()) {
|
||||||
// assert that we are holding the freelist lock
|
// assert that we are holding the freelist lock
|
||||||
} else if (thr->is_GC_task_thread()) {
|
} else if (thr->is_GC_task_thread()) {
|
||||||
assert(_protecting_lock->owned_by_self(), "FreeList RACE DETECTED");
|
assert(protecting_lock()->owned_by_self(), "FreeList RACE DETECTED");
|
||||||
} else if (thr->is_Java_thread()) {
|
} else if (thr->is_Java_thread()) {
|
||||||
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
|
assert(!SafepointSynchronize::is_at_safepoint(), "Should not be executing");
|
||||||
} else {
|
} else {
|
||||||
|
@ -350,21 +330,17 @@ void FreeList<Chunk>::print_labels_on(outputStream* st, const char* c) {
|
||||||
// to the call is a non-null string, it is printed in the first column;
|
// to the call is a non-null string, it is printed in the first column;
|
||||||
// otherwise, if the argument is null (the default), then the size of the
|
// otherwise, if the argument is null (the default), then the size of the
|
||||||
// (free list) block is printed in the first column.
|
// (free list) block is printed in the first column.
|
||||||
template <class Chunk>
|
template <class Chunk_t>
|
||||||
void FreeList<Chunk>::print_on(outputStream* st, const char* c) const {
|
void FreeList<Chunk_t>::print_on(outputStream* st, const char* c) const {
|
||||||
if (c != NULL) {
|
if (c != NULL) {
|
||||||
st->print("%16s", c);
|
st->print("%16s", c);
|
||||||
} else {
|
} else {
|
||||||
st->print(SIZE_FORMAT_W(16), size());
|
st->print(SIZE_FORMAT_W(16), size());
|
||||||
}
|
}
|
||||||
st->print("\t"
|
|
||||||
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t"
|
|
||||||
SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\t" SSIZE_FORMAT_W(14) "\n",
|
|
||||||
bfr_surp(), surplus(), desired(), prev_sweep(), before_sweep(),
|
|
||||||
count(), coal_births(), coal_deaths(), split_births(), split_deaths());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template class FreeList<Metablock>;
|
||||||
|
template class FreeList<Metachunk>;
|
||||||
#ifndef SERIALGC
|
#ifndef SERIALGC
|
||||||
// Needs to be after the definitions have been seen.
|
|
||||||
template class FreeList<FreeChunk>;
|
template class FreeList<FreeChunk>;
|
||||||
#endif // SERIALGC
|
#endif // SERIALGC
|
||||||
|
|
|
@ -40,23 +40,19 @@ class CompactibleFreeListSpace;
|
||||||
// for that implementation.
|
// for that implementation.
|
||||||
|
|
||||||
class Mutex;
|
class Mutex;
|
||||||
template <class Chunk> class TreeList;
|
|
||||||
template <class Chunk> class PrintTreeCensusClosure;
|
|
||||||
|
|
||||||
template <class Chunk>
|
template <class Chunk_t>
|
||||||
class FreeList VALUE_OBJ_CLASS_SPEC {
|
class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||||
friend class CompactibleFreeListSpace;
|
friend class CompactibleFreeListSpace;
|
||||||
friend class VMStructs;
|
friend class VMStructs;
|
||||||
friend class PrintTreeCensusClosure<Chunk>;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Chunk* _head; // Head of list of free chunks
|
Chunk_t* _head; // Head of list of free chunks
|
||||||
Chunk* _tail; // Tail of list of free chunks
|
Chunk_t* _tail; // Tail of list of free chunks
|
||||||
size_t _size; // Size in Heap words of each chunk
|
size_t _size; // Size in Heap words of each chunk
|
||||||
ssize_t _count; // Number of entries in list
|
ssize_t _count; // Number of entries in list
|
||||||
size_t _hint; // next larger size list with a positive surplus
|
|
||||||
|
|
||||||
AllocationStats _allocation_stats; // allocation-related statistics
|
protected:
|
||||||
|
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
Mutex* _protecting_lock;
|
Mutex* _protecting_lock;
|
||||||
|
@ -71,10 +67,6 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize the allocation statistics.
|
|
||||||
protected:
|
|
||||||
void init_statistics(bool split_birth = false);
|
|
||||||
void set_count(ssize_t v) { _count = v;}
|
|
||||||
void increment_count() {
|
void increment_count() {
|
||||||
_count++;
|
_count++;
|
||||||
}
|
}
|
||||||
|
@ -89,52 +81,48 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||||
// Construct a list without any entries.
|
// Construct a list without any entries.
|
||||||
FreeList();
|
FreeList();
|
||||||
// Construct a list with "fc" as the first (and lone) entry in the list.
|
// Construct a list with "fc" as the first (and lone) entry in the list.
|
||||||
FreeList(Chunk* fc);
|
FreeList(Chunk_t* fc);
|
||||||
|
|
||||||
// Reset the head, tail, hint, and count of a free list.
|
// Do initialization
|
||||||
void reset(size_t hint);
|
void initialize();
|
||||||
|
|
||||||
|
// Reset the head, tail, and count of a free list.
|
||||||
|
void reset();
|
||||||
|
|
||||||
// Declare the current free list to be protected by the given lock.
|
// Declare the current free list to be protected by the given lock.
|
||||||
#ifdef ASSERT
|
#ifdef ASSERT
|
||||||
void set_protecting_lock(Mutex* protecting_lock) {
|
Mutex* protecting_lock() const { return _protecting_lock; }
|
||||||
_protecting_lock = protecting_lock;
|
void set_protecting_lock(Mutex* v) {
|
||||||
|
_protecting_lock = v;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// Accessors.
|
// Accessors.
|
||||||
Chunk* head() const {
|
Chunk_t* head() const {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
return _head;
|
return _head;
|
||||||
}
|
}
|
||||||
void set_head(Chunk* v) {
|
void set_head(Chunk_t* v) {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
_head = v;
|
_head = v;
|
||||||
assert(!_head || _head->size() == _size, "bad chunk size");
|
assert(!_head || _head->size() == _size, "bad chunk size");
|
||||||
}
|
}
|
||||||
// Set the head of the list and set the prev field of non-null
|
// Set the head of the list and set the prev field of non-null
|
||||||
// values to NULL.
|
// values to NULL.
|
||||||
void link_head(Chunk* v) {
|
void link_head(Chunk_t* v);
|
||||||
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) {
|
|
||||||
v->link_prev(NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Chunk* tail() const {
|
Chunk_t* tail() const {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
return _tail;
|
return _tail;
|
||||||
}
|
}
|
||||||
void set_tail(Chunk* v) {
|
void set_tail(Chunk_t* v) {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
_tail = v;
|
_tail = v;
|
||||||
assert(!_tail || _tail->size() == _size, "bad chunk size");
|
assert(!_tail || _tail->size() == _size, "bad chunk size");
|
||||||
}
|
}
|
||||||
// Set the tail of the list and set the next field of non-null
|
// Set the tail of the list and set the next field of non-null
|
||||||
// values to NULL.
|
// values to NULL.
|
||||||
void link_tail(Chunk* v) {
|
void link_tail(Chunk_t* v) {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
set_tail(v);
|
set_tail(v);
|
||||||
if (v != NULL) {
|
if (v != NULL) {
|
||||||
|
@ -152,174 +140,45 @@ class FreeList VALUE_OBJ_CLASS_SPEC {
|
||||||
assert_proper_lock_protection();
|
assert_proper_lock_protection();
|
||||||
_size = v;
|
_size = v;
|
||||||
}
|
}
|
||||||
ssize_t count() const {
|
ssize_t count() const { return _count; }
|
||||||
return _count;
|
void set_count(ssize_t v) { _count = v;}
|
||||||
}
|
|
||||||
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
|
size_t get_better_size() { return size(); }
|
||||||
AllocationStats* allocation_stats() {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
return &_allocation_stats;
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t desired() const {
|
size_t returned_bytes() const { ShouldNotReachHere(); return 0; }
|
||||||
return _allocation_stats.desired();
|
void set_returned_bytes(size_t v) {}
|
||||||
}
|
void increment_returned_bytes_by(size_t v) {}
|
||||||
void set_desired(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_desired(v);
|
|
||||||
}
|
|
||||||
void compute_desired(float inter_sweep_current,
|
|
||||||
float inter_sweep_estimate,
|
|
||||||
float intra_sweep_estimate) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.compute_desired(_count,
|
|
||||||
inter_sweep_current,
|
|
||||||
inter_sweep_estimate,
|
|
||||||
intra_sweep_estimate);
|
|
||||||
}
|
|
||||||
ssize_t coal_desired() const {
|
|
||||||
return _allocation_stats.coal_desired();
|
|
||||||
}
|
|
||||||
void set_coal_desired(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_coal_desired(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
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();
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t bfr_surp() const {
|
|
||||||
return _allocation_stats.bfr_surp();
|
|
||||||
}
|
|
||||||
void set_bfr_surp(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_bfr_surp(v);
|
|
||||||
}
|
|
||||||
ssize_t prev_sweep() const {
|
|
||||||
return _allocation_stats.prev_sweep();
|
|
||||||
}
|
|
||||||
void set_prev_sweep(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_prev_sweep(v);
|
|
||||||
}
|
|
||||||
ssize_t before_sweep() const {
|
|
||||||
return _allocation_stats.before_sweep();
|
|
||||||
}
|
|
||||||
void set_before_sweep(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_before_sweep(v);
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t coal_births() const {
|
|
||||||
return _allocation_stats.coal_births();
|
|
||||||
}
|
|
||||||
void set_coal_births(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_coal_births(v);
|
|
||||||
}
|
|
||||||
void increment_coal_births() {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.increment_coal_births();
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t coal_deaths() const {
|
|
||||||
return _allocation_stats.coal_deaths();
|
|
||||||
}
|
|
||||||
void set_coal_deaths(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_coal_deaths(v);
|
|
||||||
}
|
|
||||||
void increment_coal_deaths() {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.increment_coal_deaths();
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t split_births() const {
|
|
||||||
return _allocation_stats.split_births();
|
|
||||||
}
|
|
||||||
void set_split_births(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_split_births(v);
|
|
||||||
}
|
|
||||||
void increment_split_births() {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.increment_split_births();
|
|
||||||
}
|
|
||||||
|
|
||||||
ssize_t split_deaths() const {
|
|
||||||
return _allocation_stats.split_deaths();
|
|
||||||
}
|
|
||||||
void set_split_deaths(ssize_t v) {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.set_split_deaths(v);
|
|
||||||
}
|
|
||||||
void increment_split_deaths() {
|
|
||||||
assert_proper_lock_protection();
|
|
||||||
_allocation_stats.increment_split_deaths();
|
|
||||||
}
|
|
||||||
|
|
||||||
NOT_PRODUCT(
|
|
||||||
// For debugging. The "_returned_bytes" in all the lists are summed
|
|
||||||
// and compared with the total number of bytes swept during a
|
|
||||||
// collection.
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
)
|
|
||||||
|
|
||||||
// Unlink head of list and return it. Returns NULL if
|
// Unlink head of list and return it. Returns NULL if
|
||||||
// the list is empty.
|
// the list is empty.
|
||||||
Chunk* get_chunk_at_head();
|
Chunk_t* get_chunk_at_head();
|
||||||
|
|
||||||
// Remove the first "n" or "count", whichever is smaller, chunks from the
|
// 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.
|
// list, setting "fl", which is required to be empty, to point to them.
|
||||||
void getFirstNChunksFromList(size_t n, FreeList<Chunk>* fl);
|
void getFirstNChunksFromList(size_t n, FreeList<Chunk_t>* fl);
|
||||||
|
|
||||||
// Unlink this chunk from it's free list
|
// Unlink this chunk from it's free list
|
||||||
void remove_chunk(Chunk* fc);
|
void remove_chunk(Chunk_t* fc);
|
||||||
|
|
||||||
// Add this chunk to this free list.
|
// Add this chunk to this free list.
|
||||||
void return_chunk_at_head(Chunk* fc);
|
void return_chunk_at_head(Chunk_t* fc);
|
||||||
void return_chunk_at_tail(Chunk* fc);
|
void return_chunk_at_tail(Chunk_t* fc);
|
||||||
|
|
||||||
// Similar to returnChunk* but also records some diagnostic
|
// Similar to returnChunk* but also records some diagnostic
|
||||||
// information.
|
// information.
|
||||||
void return_chunk_at_head(Chunk* fc, bool record_return);
|
void return_chunk_at_head(Chunk_t* fc, bool record_return);
|
||||||
void return_chunk_at_tail(Chunk* fc, bool record_return);
|
void return_chunk_at_tail(Chunk_t* fc, bool record_return);
|
||||||
|
|
||||||
// Prepend "fl" (whose size is required to be the same as that of "this")
|
// Prepend "fl" (whose size is required to be the same as that of "this")
|
||||||
// to the front of "this" list.
|
// to the front of "this" list.
|
||||||
void prepend(FreeList<Chunk>* fl);
|
void prepend(FreeList<Chunk_t>* fl);
|
||||||
|
|
||||||
// Verify that the chunk is in the list.
|
// Verify that the chunk is in the list.
|
||||||
// found. Return NULL if "fc" is not found.
|
// found. Return NULL if "fc" is not found.
|
||||||
bool verify_chunk_in_free_list(Chunk* fc) const;
|
bool verify_chunk_in_free_list(Chunk_t* fc) const;
|
||||||
|
|
||||||
// Stats verification
|
// Stats verification
|
||||||
void verify_stats() const PRODUCT_RETURN;
|
// void verify_stats() const { ShouldNotReachHere(); };
|
||||||
|
|
||||||
// Printing support
|
// Printing support
|
||||||
static void print_labels_on(outputStream* st, const char* c);
|
static void print_labels_on(outputStream* st, const char* c);
|
||||||
|
|
103
hotspot/src/share/vm/memory/metablock.hpp
Normal file
103
hotspot/src/share/vm/memory/metablock.hpp
Normal file
|
@ -0,0 +1,103 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef SHARE_VM_MEMORY_METABLOCK_HPP
|
||||||
|
#define SHARE_VM_MEMORY_METABLOCK_HPP
|
||||||
|
|
||||||
|
// Metablock are the unit of allocation from a Chunk. It is initialized
|
||||||
|
// with the size of the requested allocation. That size is overwritten
|
||||||
|
// once the allocation returns.
|
||||||
|
//
|
||||||
|
// A Metablock may be reused by its SpaceManager but are never moved between
|
||||||
|
// SpaceManagers. There is no explicit link to the Metachunk
|
||||||
|
// from which it was allocated. Metablock may be deallocated and
|
||||||
|
// put on a freelist but the space is never freed, rather
|
||||||
|
// the Metachunk it is a part of will be deallocated when it's
|
||||||
|
// associated class loader is collected.
|
||||||
|
|
||||||
|
class Metablock VALUE_OBJ_CLASS_SPEC {
|
||||||
|
friend class VMStructs;
|
||||||
|
private:
|
||||||
|
// Used to align the allocation (see below).
|
||||||
|
union block_t {
|
||||||
|
void* _data[3];
|
||||||
|
struct header_t {
|
||||||
|
size_t _word_size;
|
||||||
|
Metablock* _next;
|
||||||
|
Metablock* _prev;
|
||||||
|
} _header;
|
||||||
|
} _block;
|
||||||
|
static size_t _min_block_byte_size;
|
||||||
|
static size_t _overhead;
|
||||||
|
|
||||||
|
typedef union block_t Block;
|
||||||
|
typedef struct header_t Header;
|
||||||
|
const Block* block() const { return &_block; }
|
||||||
|
const Block::header_t* header() const { return &(block()->_header); }
|
||||||
|
public:
|
||||||
|
|
||||||
|
static Metablock* initialize(MetaWord* p, size_t word_size);
|
||||||
|
|
||||||
|
// This places the body of the block at a 2 word boundary
|
||||||
|
// because every block starts on a 2 word boundary. Work out
|
||||||
|
// how to make the body on a 2 word boundary if the block
|
||||||
|
// starts on a arbitrary boundary. JJJ
|
||||||
|
|
||||||
|
size_t word_size() const { return header()->_word_size; }
|
||||||
|
void set_word_size(size_t v) { _block._header._word_size = v; }
|
||||||
|
size_t size() const volatile { return _block._header._word_size; }
|
||||||
|
void set_size(size_t v) { _block._header._word_size = v; }
|
||||||
|
Metablock* next() const { return header()->_next; }
|
||||||
|
void set_next(Metablock* v) { _block._header._next = v; }
|
||||||
|
Metablock* prev() const { return header()->_prev; }
|
||||||
|
void set_prev(Metablock* v) { _block._header._prev = v; }
|
||||||
|
|
||||||
|
static size_t min_block_byte_size() { return _min_block_byte_size; }
|
||||||
|
static size_t overhead() { return _overhead; }
|
||||||
|
|
||||||
|
bool is_free() { return header()->_word_size != 0; }
|
||||||
|
void clear_next() { set_next(NULL); }
|
||||||
|
void link_prev(Metablock* ptr) { set_prev(ptr); }
|
||||||
|
uintptr_t* end() { return ((uintptr_t*) this) + size(); }
|
||||||
|
bool cantCoalesce() const { return false; }
|
||||||
|
void link_next(Metablock* ptr) { set_next(ptr); }
|
||||||
|
void link_after(Metablock* ptr){
|
||||||
|
link_next(ptr);
|
||||||
|
if (ptr != NULL) ptr->link_prev(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Should not be needed in a free list of Metablocks
|
||||||
|
void markNotFree() { ShouldNotReachHere(); }
|
||||||
|
|
||||||
|
// Debug support
|
||||||
|
#ifdef ASSERT
|
||||||
|
void* prev_addr() const { return (void*)&_block._header._prev; }
|
||||||
|
void* next_addr() const { return (void*)&_block._header._next; }
|
||||||
|
void* size_addr() const { return (void*)&_block._header._word_size; }
|
||||||
|
#endif
|
||||||
|
bool verify_chunk_in_free_list(Metablock* tc) const { return true; }
|
||||||
|
bool verify_par_locked() { return true; }
|
||||||
|
|
||||||
|
void assert_is_mangled() const {/* Don't check "\*/}
|
||||||
|
};
|
||||||
|
#endif // SHARE_VM_MEMORY_METABLOCK_HPP
|
133
hotspot/src/share/vm/memory/metachunk.hpp
Normal file
133
hotspot/src/share/vm/memory/metachunk.hpp
Normal file
|
@ -0,0 +1,133 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
* 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.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#ifndef SHARE_VM_MEMORY_METACHUNK_HPP
|
||||||
|
#define SHARE_VM_MEMORY_METACHUNK_HPP
|
||||||
|
|
||||||
|
// 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 |
|
||||||
|
// | | | |
|
||||||
|
// | | | | capacity
|
||||||
|
// | | | |
|
||||||
|
// | | <- top --+ |
|
||||||
|
// | | ---+ |
|
||||||
|
// | | | used |
|
||||||
|
// | | | |
|
||||||
|
// | | | |
|
||||||
|
// +--------------+ <- bottom ---+ ---+
|
||||||
|
|
||||||
|
class Metachunk VALUE_OBJ_CLASS_SPEC {
|
||||||
|
// link to support lists of chunks
|
||||||
|
Metachunk* _next;
|
||||||
|
Metachunk* _prev;
|
||||||
|
|
||||||
|
MetaWord* _bottom;
|
||||||
|
MetaWord* _end;
|
||||||
|
MetaWord* _top;
|
||||||
|
size_t _word_size;
|
||||||
|
// Used in a guarantee() so included in the Product builds
|
||||||
|
// even through it is only for debugging.
|
||||||
|
bool _is_free;
|
||||||
|
|
||||||
|
// 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.
|
||||||
|
static size_t _overhead;
|
||||||
|
|
||||||
|
void set_bottom(MetaWord* v) { _bottom = v; }
|
||||||
|
void set_end(MetaWord* v) { _end = v; }
|
||||||
|
void set_top(MetaWord* v) { _top = v; }
|
||||||
|
void set_word_size(size_t v) { _word_size = v; }
|
||||||
|
public:
|
||||||
|
#ifdef ASSERT
|
||||||
|
Metachunk() : _bottom(NULL), _end(NULL), _top(NULL), _is_free(false) {}
|
||||||
|
#else
|
||||||
|
Metachunk() : _bottom(NULL), _end(NULL), _top(NULL) {}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Used to add a Metachunk to a list of Metachunks
|
||||||
|
void set_next(Metachunk* v) { _next = v; assert(v != this, "Boom");}
|
||||||
|
void set_prev(Metachunk* v) { _prev = v; assert(v != this, "Boom");}
|
||||||
|
|
||||||
|
MetaWord* allocate(size_t word_size);
|
||||||
|
static Metachunk* initialize(MetaWord* ptr, size_t word_size);
|
||||||
|
|
||||||
|
// Accessors
|
||||||
|
Metachunk* next() const { return _next; }
|
||||||
|
Metachunk* prev() const { return _prev; }
|
||||||
|
MetaWord* bottom() const { return _bottom; }
|
||||||
|
MetaWord* end() const { return _end; }
|
||||||
|
MetaWord* top() const { return _top; }
|
||||||
|
size_t word_size() const { return _word_size; }
|
||||||
|
size_t size() const volatile { return _word_size; }
|
||||||
|
void set_size(size_t v) { _word_size = v; }
|
||||||
|
bool is_free() { return _is_free; }
|
||||||
|
void set_is_free(bool v) { _is_free = v; }
|
||||||
|
static size_t overhead() { return _overhead; }
|
||||||
|
void clear_next() { set_next(NULL); }
|
||||||
|
void link_prev(Metachunk* ptr) { set_prev(ptr); }
|
||||||
|
uintptr_t* end() { return ((uintptr_t*) this) + size(); }
|
||||||
|
bool cantCoalesce() const { return false; }
|
||||||
|
void link_next(Metachunk* ptr) { set_next(ptr); }
|
||||||
|
void link_after(Metachunk* ptr){
|
||||||
|
link_next(ptr);
|
||||||
|
if (ptr != NULL) ptr->link_prev(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reset top to bottom so chunk can be reused.
|
||||||
|
void reset_empty() { _top = (_bottom + _overhead); }
|
||||||
|
bool is_empty() { return _top == (_bottom + _overhead); }
|
||||||
|
|
||||||
|
// used (has been allocated)
|
||||||
|
// free (available for future allocations)
|
||||||
|
// capacity (total size of chunk)
|
||||||
|
size_t used_word_size();
|
||||||
|
size_t free_word_size();
|
||||||
|
size_t capacity_word_size();
|
||||||
|
|
||||||
|
// Debug support
|
||||||
|
#ifdef ASSERT
|
||||||
|
void* prev_addr() const { return (void*)&_prev; }
|
||||||
|
void* next_addr() const { return (void*)&_next; }
|
||||||
|
void* size_addr() const { return (void*)&_word_size; }
|
||||||
|
#endif
|
||||||
|
bool verify_chunk_in_free_list(Metachunk* tc) const { return true; }
|
||||||
|
bool verify_par_locked() { return true; }
|
||||||
|
|
||||||
|
void assert_is_mangled() const {/* Don't check "\*/}
|
||||||
|
|
||||||
|
#ifdef ASSERT
|
||||||
|
void mangle();
|
||||||
|
#endif // ASSERT
|
||||||
|
|
||||||
|
void print_on(outputStream* st) const;
|
||||||
|
void verify();
|
||||||
|
};
|
||||||
|
#endif // SHARE_VM_MEMORY_METACHUNK_HPP
|
File diff suppressed because it is too large
Load diff
|
@ -57,12 +57,10 @@
|
||||||
//
|
//
|
||||||
|
|
||||||
class ClassLoaderData;
|
class ClassLoaderData;
|
||||||
|
class Metablock;
|
||||||
class MetaWord;
|
class MetaWord;
|
||||||
class Mutex;
|
class Mutex;
|
||||||
class outputStream;
|
class outputStream;
|
||||||
class FreeChunk;
|
|
||||||
template <class Chunk_t> class FreeList;
|
|
||||||
template <class Chunk_t> class BinaryTreeDictionary;
|
|
||||||
class SpaceManager;
|
class SpaceManager;
|
||||||
|
|
||||||
// Metaspaces each have a SpaceManager and allocations
|
// Metaspaces each have a SpaceManager and allocations
|
||||||
|
@ -128,7 +126,7 @@ class Metaspace : public CHeapObj<mtClass> {
|
||||||
size_t capacity_words(MetadataType mdtype) const;
|
size_t capacity_words(MetadataType mdtype) const;
|
||||||
size_t waste_words(MetadataType mdtype) const;
|
size_t waste_words(MetadataType mdtype) const;
|
||||||
|
|
||||||
static MetaWord* allocate(ClassLoaderData* loader_data, size_t size,
|
static Metablock* allocate(ClassLoaderData* loader_data, size_t size,
|
||||||
bool read_only, MetadataType mdtype, TRAPS);
|
bool read_only, MetadataType mdtype, TRAPS);
|
||||||
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
|
void deallocate(MetaWord* ptr, size_t byte_size, bool is_class);
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,7 @@
|
||||||
#include "memory/generation.hpp"
|
#include "memory/generation.hpp"
|
||||||
#include "memory/generationSpec.hpp"
|
#include "memory/generationSpec.hpp"
|
||||||
#include "memory/heap.hpp"
|
#include "memory/heap.hpp"
|
||||||
|
#include "memory/metablock.hpp"
|
||||||
#include "memory/space.hpp"
|
#include "memory/space.hpp"
|
||||||
#include "memory/tenuredGeneration.hpp"
|
#include "memory/tenuredGeneration.hpp"
|
||||||
#include "memory/universe.hpp"
|
#include "memory/universe.hpp"
|
||||||
|
@ -249,6 +250,7 @@ typedef TwoOopHashtable<Klass*, mtClass> KlassTwoOopHashtable;
|
||||||
typedef Hashtable<Klass*, mtClass> KlassHashtable;
|
typedef Hashtable<Klass*, mtClass> KlassHashtable;
|
||||||
typedef HashtableEntry<Klass*, mtClass> KlassHashtableEntry;
|
typedef HashtableEntry<Klass*, mtClass> KlassHashtableEntry;
|
||||||
typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||||
|
typedef BinaryTreeDictionary<Metablock, FreeList> MetablockTreeDictionary;
|
||||||
|
|
||||||
//--------------------------------------------------------------------------------
|
//--------------------------------------------------------------------------------
|
||||||
// VM_STRUCTS
|
// VM_STRUCTS
|
||||||
|
@ -1237,7 +1239,15 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||||
nonstatic_field(AccessFlags, _flags, jint) \
|
nonstatic_field(AccessFlags, _flags, jint) \
|
||||||
nonstatic_field(elapsedTimer, _counter, jlong) \
|
nonstatic_field(elapsedTimer, _counter, jlong) \
|
||||||
nonstatic_field(elapsedTimer, _active, bool) \
|
nonstatic_field(elapsedTimer, _active, bool) \
|
||||||
nonstatic_field(InvocationCounter, _counter, unsigned int)
|
nonstatic_field(InvocationCounter, _counter, unsigned int) \
|
||||||
|
volatile_nonstatic_field(FreeChunk, _size, size_t) \
|
||||||
|
nonstatic_field(FreeChunk, _next, FreeChunk*) \
|
||||||
|
nonstatic_field(FreeChunk, _prev, FreeChunk*) \
|
||||||
|
nonstatic_field(FreeList<FreeChunk>, _size, size_t) \
|
||||||
|
nonstatic_field(FreeList<Metablock>, _size, size_t) \
|
||||||
|
nonstatic_field(FreeList<FreeChunk>, _count, ssize_t) \
|
||||||
|
nonstatic_field(FreeList<Metablock>, _count, ssize_t) \
|
||||||
|
nonstatic_field(MetablockTreeDictionary, _total_size, size_t)
|
||||||
|
|
||||||
/* NOTE that we do not use the last_entry() macro here; it is used */
|
/* NOTE that we do not use the last_entry() macro here; it is used */
|
||||||
/* in vmStructs_<os>_<cpu>.hpp's VM_STRUCTS_OS_CPU macro (and must */
|
/* in vmStructs_<os>_<cpu>.hpp's VM_STRUCTS_OS_CPU macro (and must */
|
||||||
|
@ -2080,7 +2090,24 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||||
declare_toplevel_type(Universe) \
|
declare_toplevel_type(Universe) \
|
||||||
declare_toplevel_type(vframeArray) \
|
declare_toplevel_type(vframeArray) \
|
||||||
declare_toplevel_type(vframeArrayElement) \
|
declare_toplevel_type(vframeArrayElement) \
|
||||||
declare_toplevel_type(Annotations*)
|
declare_toplevel_type(Annotations*) \
|
||||||
|
\
|
||||||
|
/***************/ \
|
||||||
|
/* Miscellaneous types */ \
|
||||||
|
/***************/ \
|
||||||
|
\
|
||||||
|
/* freelist */ \
|
||||||
|
declare_toplevel_type(FreeChunk*) \
|
||||||
|
declare_toplevel_type(Metablock*) \
|
||||||
|
declare_toplevel_type(FreeBlockDictionary<FreeChunk>*) \
|
||||||
|
declare_toplevel_type(FreeList<FreeChunk>*) \
|
||||||
|
declare_toplevel_type(FreeList<FreeChunk>) \
|
||||||
|
declare_toplevel_type(FreeBlockDictionary<Metablock>*) \
|
||||||
|
declare_toplevel_type(FreeList<Metablock>*) \
|
||||||
|
declare_toplevel_type(FreeList<Metablock>) \
|
||||||
|
declare_toplevel_type(MetablockTreeDictionary*) \
|
||||||
|
declare_type(MetablockTreeDictionary, FreeBlockDictionary<Metablock>) \
|
||||||
|
declare_type(MetablockTreeDictionary, FreeBlockDictionary<Metablock>)
|
||||||
|
|
||||||
|
|
||||||
/* NOTE that we do not use the last_entry() macro here; it is used */
|
/* NOTE that we do not use the last_entry() macro here; it is used */
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue