Merge
This commit is contained in:
commit
b59b80b068
@ -64,8 +64,8 @@ public class DefNewGeneration extends Generation {
|
||||
}
|
||||
|
||||
// Accessing spaces
|
||||
public EdenSpace eden() {
|
||||
return (EdenSpace) VMObjectFactory.newObject(EdenSpace.class, edenSpaceField.getValue(addr));
|
||||
public ContiguousSpace eden() {
|
||||
return (ContiguousSpace) VMObjectFactory.newObject(ContiguousSpace.class, edenSpaceField.getValue(addr));
|
||||
}
|
||||
|
||||
public ContiguousSpace from() {
|
||||
|
@ -1,40 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
package sun.jvm.hotspot.memory;
|
||||
|
||||
import java.util.*;
|
||||
import sun.jvm.hotspot.debugger.*;
|
||||
import sun.jvm.hotspot.runtime.*;
|
||||
import sun.jvm.hotspot.types.*;
|
||||
|
||||
/** <P> Class EdenSpace describes eden-space in new
|
||||
generation. (Currently it does not add any significant
|
||||
functionality beyond ContiguousSpace.) */
|
||||
|
||||
public class EdenSpace extends ContiguousSpace {
|
||||
public EdenSpace(Address addr) {
|
||||
super(addr);
|
||||
}
|
||||
}
|
@ -3513,7 +3513,7 @@ void TemplateTable::_new() {
|
||||
Rtags = R3_ARG1,
|
||||
Rindex = R5_ARG3;
|
||||
|
||||
const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
|
||||
const bool allow_shared_alloc = Universe::heap()->supports_inline_contig_alloc();
|
||||
|
||||
// --------------------------------------------------------------------------
|
||||
// Check if fast case is possible.
|
||||
|
@ -3196,7 +3196,7 @@ void MacroAssembler::eden_allocate(
|
||||
assert(0 <= con_size_in_bytes && Assembler::is_simm13(con_size_in_bytes), "illegal object size");
|
||||
assert((con_size_in_bytes & MinObjAlignmentInBytesMask) == 0, "object size is not multiple of alignment");
|
||||
|
||||
if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
|
||||
if (!Universe::heap()->supports_inline_contig_alloc()) {
|
||||
// No allocation in the shared eden.
|
||||
ba(slow_case);
|
||||
delayed()->nop();
|
||||
@ -3331,7 +3331,7 @@ void MacroAssembler::tlab_refill(Label& retry, Label& try_eden, Label& slow_case
|
||||
assert_different_registers(top, t1, t2, t3, G4, G5 /* preserve G4 and G5 */);
|
||||
Label do_refill, discard_tlab;
|
||||
|
||||
if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
|
||||
if (!Universe::heap()->supports_inline_contig_alloc()) {
|
||||
// No allocation in the shared eden.
|
||||
ba(slow_case);
|
||||
delayed()->nop();
|
||||
|
@ -3309,7 +3309,7 @@ void TemplateTable::_new() {
|
||||
// (creates a new TLAB, etc.)
|
||||
|
||||
const bool allow_shared_alloc =
|
||||
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
|
||||
Universe::heap()->supports_inline_contig_alloc();
|
||||
|
||||
if(UseTLAB) {
|
||||
Register RoldTopValue = RallocatedObject;
|
||||
|
@ -2964,7 +2964,7 @@ void MacroAssembler::eden_allocate(Register obj,
|
||||
Label& slow_case) {
|
||||
assert(obj == rax, "obj must be in rax, for cmpxchg");
|
||||
assert_different_registers(obj, var_size_in_bytes, t1);
|
||||
if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
|
||||
if (!Universe::heap()->supports_inline_contig_alloc()) {
|
||||
jmp(slow_case);
|
||||
} else {
|
||||
Register end = t1;
|
||||
@ -4437,7 +4437,7 @@ Register MacroAssembler::tlab_refill(Label& retry,
|
||||
assert_different_registers(top, thread_reg, t1, t2, /* preserve: */ rbx, rdx);
|
||||
Label do_refill, discard_tlab;
|
||||
|
||||
if (CMSIncrementalMode || !Universe::heap()->supports_inline_contig_alloc()) {
|
||||
if (!Universe::heap()->supports_inline_contig_alloc()) {
|
||||
// No allocation in the shared eden.
|
||||
jmp(slow_case);
|
||||
}
|
||||
|
@ -3214,7 +3214,7 @@ void TemplateTable::_new() {
|
||||
// (creates a new TLAB, etc.)
|
||||
|
||||
const bool allow_shared_alloc =
|
||||
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
|
||||
Universe::heap()->supports_inline_contig_alloc();
|
||||
|
||||
const Register thread = rcx;
|
||||
if (UseTLAB || allow_shared_alloc) {
|
||||
|
@ -3269,7 +3269,7 @@ void TemplateTable::_new() {
|
||||
// (creates a new TLAB, etc.)
|
||||
|
||||
const bool allow_shared_alloc =
|
||||
Universe::heap()->supports_inline_contig_alloc() && !CMSIncrementalMode;
|
||||
Universe::heap()->supports_inline_contig_alloc();
|
||||
|
||||
if (UseTLAB) {
|
||||
__ movptr(rax, Address(r15_thread, in_bytes(JavaThread::tlab_top_offset())));
|
||||
|
@ -7,7 +7,6 @@
|
||||
-Xbootclasspath/p:<directories and zip/jar files separated by ;>
|
||||
prepend in front of bootstrap class path
|
||||
-Xnoclassgc disable class garbage collection
|
||||
-Xincgc enable incremental garbage collection
|
||||
-Xloggc:<file> log GC status to a file with time stamps
|
||||
-Xbatch disable background compilation
|
||||
-Xms<size> set initial Java heap size
|
||||
|
@ -89,9 +89,3 @@ void ConcurrentMarkSweepPolicy::initialize_gc_policy_counters() {
|
||||
_gc_policy_counters = new GCPolicyCounters("Copy:CMS", 2, 3);
|
||||
}
|
||||
}
|
||||
|
||||
// Returns true if the incremental mode is enabled.
|
||||
bool ConcurrentMarkSweepPolicy::has_soft_ended_eden()
|
||||
{
|
||||
return CMSIncrementalMode;
|
||||
}
|
||||
|
@ -42,9 +42,6 @@ class ConcurrentMarkSweepPolicy : public GenCollectorPolicy {
|
||||
virtual void initialize_size_policy(size_t init_eden_size,
|
||||
size_t init_promo_size,
|
||||
size_t init_survivor_size);
|
||||
|
||||
// Returns true if the incremental mode is enabled.
|
||||
virtual bool has_soft_ended_eden();
|
||||
};
|
||||
|
||||
#endif // SHARE_VM_GC_IMPLEMENTATION_CONCURRENTMARKSWEEP_CMSCOLLECTORPOLICY_HPP
|
||||
|
@ -2083,17 +2083,13 @@ bool CompactibleFreeListSpace::should_concurrent_collect() const {
|
||||
}
|
||||
|
||||
// Support for compaction
|
||||
|
||||
void CompactibleFreeListSpace::prepare_for_compaction(CompactPoint* cp) {
|
||||
SCAN_AND_FORWARD(cp,end,block_is_obj,block_size);
|
||||
scan_and_forward(this, cp);
|
||||
// Prepare_for_compaction() uses the space between live objects
|
||||
// so that later phase can skip dead space quickly. So verification
|
||||
// of the free lists doesn't work after.
|
||||
}
|
||||
|
||||
#define obj_size(q) adjustObjectSize(oop(q)->size())
|
||||
#define adjust_obj_size(s) adjustObjectSize(s)
|
||||
|
||||
void CompactibleFreeListSpace::adjust_pointers() {
|
||||
// In other versions of adjust_pointers(), a bail out
|
||||
// based on the amount of live data in the generation
|
||||
@ -2101,12 +2097,12 @@ void CompactibleFreeListSpace::adjust_pointers() {
|
||||
// Cannot test used() == 0 here because the free lists have already
|
||||
// been mangled by the compaction.
|
||||
|
||||
SCAN_AND_ADJUST_POINTERS(adjust_obj_size);
|
||||
scan_and_adjust_pointers(this);
|
||||
// See note about verification in prepare_for_compaction().
|
||||
}
|
||||
|
||||
void CompactibleFreeListSpace::compact() {
|
||||
SCAN_AND_COMPACT(obj_size);
|
||||
scan_and_compact(this);
|
||||
}
|
||||
|
||||
// Fragmentation metric = 1 - [sum of (fbs**2) / (sum of fbs)**2]
|
||||
|
@ -73,6 +73,13 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
friend class CMSCollector;
|
||||
// Local alloc buffer for promotion into this space.
|
||||
friend class CFLS_LAB;
|
||||
// Allow scan_and_* functions to call (private) overrides of the auxiliary functions on this class
|
||||
template <typename SpaceType>
|
||||
friend void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space);
|
||||
template <typename SpaceType>
|
||||
friend void CompactibleSpace::scan_and_compact(SpaceType* space);
|
||||
template <typename SpaceType>
|
||||
friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp);
|
||||
|
||||
// "Size" of chunks of work (executed during parallel remark phases
|
||||
// of CMS collection); this probably belongs in CMSCollector, although
|
||||
@ -288,6 +295,28 @@ class CompactibleFreeListSpace: public CompactibleSpace {
|
||||
_bt.freed(start, size);
|
||||
}
|
||||
|
||||
// Auxiliary functions for scan_and_{forward,adjust_pointers,compact} support.
|
||||
// See comments for CompactibleSpace for more information.
|
||||
inline HeapWord* scan_limit() const {
|
||||
return end();
|
||||
}
|
||||
|
||||
inline bool scanned_block_is_obj(const HeapWord* addr) const {
|
||||
return CompactibleFreeListSpace::block_is_obj(addr); // Avoid virtual call
|
||||
}
|
||||
|
||||
inline size_t scanned_block_size(const HeapWord* addr) const {
|
||||
return CompactibleFreeListSpace::block_size(addr); // Avoid virtual call
|
||||
}
|
||||
|
||||
inline size_t adjust_obj_size(size_t size) const {
|
||||
return adjustObjectSize(size);
|
||||
}
|
||||
|
||||
inline size_t obj_size(const HeapWord* addr) const {
|
||||
return adjustObjectSize(oop(addr)->size());
|
||||
}
|
||||
|
||||
protected:
|
||||
// Reset the indexed free list to its initial empty condition.
|
||||
void resetIndexedFreeListArray();
|
||||
|
@ -167,16 +167,6 @@ class CMSTokenSyncWithLocks: public CMSTokenSync {
|
||||
};
|
||||
|
||||
|
||||
// Wrapper class to temporarily disable icms during a foreground cms collection.
|
||||
class ICMSDisabler: public StackObj {
|
||||
public:
|
||||
// The ctor disables icms and wakes up the thread so it notices the change;
|
||||
// the dtor re-enables icms. Note that the CMSCollector methods will check
|
||||
// CMSIncrementalMode.
|
||||
ICMSDisabler() { CMSCollector::disable_icms(); CMSCollector::start_icms(); }
|
||||
~ICMSDisabler() { CMSCollector::enable_icms(); }
|
||||
};
|
||||
|
||||
//////////////////////////////////////////////////////////////////
|
||||
// Concurrent Mark-Sweep Generation /////////////////////////////
|
||||
//////////////////////////////////////////////////////////////////
|
||||
@ -363,7 +353,6 @@ CMSStats::CMSStats(ConcurrentMarkSweepGeneration* cms_gen, unsigned int alpha):
|
||||
_cms_used_at_gc0_end = 0;
|
||||
_allow_duty_cycle_reduction = false;
|
||||
_valid_bits = 0;
|
||||
_icms_duty_cycle = CMSIncrementalDutyCycle;
|
||||
}
|
||||
|
||||
double CMSStats::cms_free_adjustment_factor(size_t free) const {
|
||||
@ -442,86 +431,17 @@ double CMSStats::time_until_cms_start() const {
|
||||
return work - deadline;
|
||||
}
|
||||
|
||||
// Return a duty cycle based on old_duty_cycle and new_duty_cycle, limiting the
|
||||
// amount of change to prevent wild oscillation.
|
||||
unsigned int CMSStats::icms_damped_duty_cycle(unsigned int old_duty_cycle,
|
||||
unsigned int new_duty_cycle) {
|
||||
assert(old_duty_cycle <= 100, "bad input value");
|
||||
assert(new_duty_cycle <= 100, "bad input value");
|
||||
|
||||
// Note: use subtraction with caution since it may underflow (values are
|
||||
// unsigned). Addition is safe since we're in the range 0-100.
|
||||
unsigned int damped_duty_cycle = new_duty_cycle;
|
||||
if (new_duty_cycle < old_duty_cycle) {
|
||||
const unsigned int largest_delta = MAX2(old_duty_cycle / 4, 5U);
|
||||
if (new_duty_cycle + largest_delta < old_duty_cycle) {
|
||||
damped_duty_cycle = old_duty_cycle - largest_delta;
|
||||
}
|
||||
} else if (new_duty_cycle > old_duty_cycle) {
|
||||
const unsigned int largest_delta = MAX2(old_duty_cycle / 4, 15U);
|
||||
if (new_duty_cycle > old_duty_cycle + largest_delta) {
|
||||
damped_duty_cycle = MIN2(old_duty_cycle + largest_delta, 100U);
|
||||
}
|
||||
}
|
||||
assert(damped_duty_cycle <= 100, "invalid duty cycle computed");
|
||||
|
||||
if (CMSTraceIncrementalPacing) {
|
||||
gclog_or_tty->print(" [icms_damped_duty_cycle(%d,%d) = %d] ",
|
||||
old_duty_cycle, new_duty_cycle, damped_duty_cycle);
|
||||
}
|
||||
return damped_duty_cycle;
|
||||
}
|
||||
|
||||
unsigned int CMSStats::icms_update_duty_cycle_impl() {
|
||||
assert(CMSIncrementalPacing && valid(),
|
||||
"should be handled in icms_update_duty_cycle()");
|
||||
|
||||
double cms_time_so_far = cms_timer().seconds();
|
||||
double scaled_duration = cms_duration_per_mb() * _cms_used_at_gc0_end / M;
|
||||
double scaled_duration_remaining = fabsd(scaled_duration - cms_time_so_far);
|
||||
|
||||
// Avoid division by 0.
|
||||
double time_until_full = MAX2(time_until_cms_gen_full(), 0.01);
|
||||
double duty_cycle_dbl = 100.0 * scaled_duration_remaining / time_until_full;
|
||||
|
||||
unsigned int new_duty_cycle = MIN2((unsigned int)duty_cycle_dbl, 100U);
|
||||
if (new_duty_cycle > _icms_duty_cycle) {
|
||||
// Avoid very small duty cycles (1 or 2); 0 is allowed.
|
||||
if (new_duty_cycle > 2) {
|
||||
_icms_duty_cycle = icms_damped_duty_cycle(_icms_duty_cycle,
|
||||
new_duty_cycle);
|
||||
}
|
||||
} else if (_allow_duty_cycle_reduction) {
|
||||
// The duty cycle is reduced only once per cms cycle (see record_cms_end()).
|
||||
new_duty_cycle = icms_damped_duty_cycle(_icms_duty_cycle, new_duty_cycle);
|
||||
// Respect the minimum duty cycle.
|
||||
unsigned int min_duty_cycle = (unsigned int)CMSIncrementalDutyCycleMin;
|
||||
_icms_duty_cycle = MAX2(new_duty_cycle, min_duty_cycle);
|
||||
}
|
||||
|
||||
if (PrintGCDetails || CMSTraceIncrementalPacing) {
|
||||
gclog_or_tty->print(" icms_dc=%d ", _icms_duty_cycle);
|
||||
}
|
||||
|
||||
_allow_duty_cycle_reduction = false;
|
||||
return _icms_duty_cycle;
|
||||
}
|
||||
|
||||
#ifndef PRODUCT
|
||||
void CMSStats::print_on(outputStream *st) const {
|
||||
st->print(" gc0_alpha=%d,cms_alpha=%d", _gc0_alpha, _cms_alpha);
|
||||
st->print(",gc0_dur=%g,gc0_per=%g,gc0_promo=" SIZE_FORMAT,
|
||||
gc0_duration(), gc0_period(), gc0_promoted());
|
||||
st->print(",cms_dur=%g,cms_dur_per_mb=%g,cms_per=%g,cms_alloc=" SIZE_FORMAT,
|
||||
cms_duration(), cms_duration_per_mb(),
|
||||
cms_period(), cms_allocated());
|
||||
st->print(",cms_dur=%g,cms_per=%g,cms_alloc=" SIZE_FORMAT,
|
||||
cms_duration(), cms_period(), cms_allocated());
|
||||
st->print(",cms_since_beg=%g,cms_since_end=%g",
|
||||
cms_time_since_begin(), cms_time_since_end());
|
||||
st->print(",cms_used_beg=" SIZE_FORMAT ",cms_used_end=" SIZE_FORMAT,
|
||||
_cms_used_at_gc0_begin, _cms_used_at_gc0_end);
|
||||
if (CMSIncrementalMode) {
|
||||
st->print(",dc=%d", icms_duty_cycle());
|
||||
}
|
||||
|
||||
if (valid()) {
|
||||
st->print(",promo_rate=%g,cms_alloc_rate=%g",
|
||||
@ -579,8 +499,6 @@ CMSCollector::CMSCollector(ConcurrentMarkSweepGeneration* cmsGen,
|
||||
#endif
|
||||
_collection_count_start(0),
|
||||
_verifying(false),
|
||||
_icms_start_limit(NULL),
|
||||
_icms_stop_limit(NULL),
|
||||
_verification_mark_bm(0, Mutex::leaf + 1, "CMS_verification_mark_bm_lock"),
|
||||
_completed_initialization(false),
|
||||
_collector_policy(cp),
|
||||
@ -1116,137 +1034,6 @@ void CMSCollector::promoted(bool par, HeapWord* start,
|
||||
}
|
||||
}
|
||||
|
||||
static inline size_t percent_of_space(Space* space, HeapWord* addr)
|
||||
{
|
||||
size_t delta = pointer_delta(addr, space->bottom());
|
||||
return (size_t)(delta * 100.0 / (space->capacity() / HeapWordSize));
|
||||
}
|
||||
|
||||
void CMSCollector::icms_update_allocation_limits()
|
||||
{
|
||||
Generation* young = GenCollectedHeap::heap()->get_gen(0);
|
||||
EdenSpace* eden = young->as_DefNewGeneration()->eden();
|
||||
|
||||
const unsigned int duty_cycle = stats().icms_update_duty_cycle();
|
||||
if (CMSTraceIncrementalPacing) {
|
||||
stats().print();
|
||||
}
|
||||
|
||||
assert(duty_cycle <= 100, "invalid duty cycle");
|
||||
if (duty_cycle != 0) {
|
||||
// The duty_cycle is a percentage between 0 and 100; convert to words and
|
||||
// then compute the offset from the endpoints of the space.
|
||||
size_t free_words = eden->free() / HeapWordSize;
|
||||
double free_words_dbl = (double)free_words;
|
||||
size_t duty_cycle_words = (size_t)(free_words_dbl * duty_cycle / 100.0);
|
||||
size_t offset_words = (free_words - duty_cycle_words) / 2;
|
||||
|
||||
_icms_start_limit = eden->top() + offset_words;
|
||||
_icms_stop_limit = eden->end() - offset_words;
|
||||
|
||||
// The limits may be adjusted (shifted to the right) by
|
||||
// CMSIncrementalOffset, to allow the application more mutator time after a
|
||||
// young gen gc (when all mutators were stopped) and before CMS starts and
|
||||
// takes away one or more cpus.
|
||||
if (CMSIncrementalOffset != 0) {
|
||||
double adjustment_dbl = free_words_dbl * CMSIncrementalOffset / 100.0;
|
||||
size_t adjustment = (size_t)adjustment_dbl;
|
||||
HeapWord* tmp_stop = _icms_stop_limit + adjustment;
|
||||
if (tmp_stop > _icms_stop_limit && tmp_stop < eden->end()) {
|
||||
_icms_start_limit += adjustment;
|
||||
_icms_stop_limit = tmp_stop;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (duty_cycle == 0 || (_icms_start_limit == _icms_stop_limit)) {
|
||||
_icms_start_limit = _icms_stop_limit = eden->end();
|
||||
}
|
||||
|
||||
// Install the new start limit.
|
||||
eden->set_soft_end(_icms_start_limit);
|
||||
|
||||
if (CMSTraceIncrementalMode) {
|
||||
gclog_or_tty->print(" icms alloc limits: "
|
||||
PTR_FORMAT "," PTR_FORMAT
|
||||
" (" SIZE_FORMAT "%%," SIZE_FORMAT "%%) ",
|
||||
p2i(_icms_start_limit), p2i(_icms_stop_limit),
|
||||
percent_of_space(eden, _icms_start_limit),
|
||||
percent_of_space(eden, _icms_stop_limit));
|
||||
if (Verbose) {
|
||||
gclog_or_tty->print("eden: ");
|
||||
eden->print_on(gclog_or_tty);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Any changes here should try to maintain the invariant
|
||||
// that if this method is called with _icms_start_limit
|
||||
// and _icms_stop_limit both NULL, then it should return NULL
|
||||
// and not notify the icms thread.
|
||||
HeapWord*
|
||||
CMSCollector::allocation_limit_reached(Space* space, HeapWord* top,
|
||||
size_t word_size)
|
||||
{
|
||||
// A start_limit equal to end() means the duty cycle is 0, so treat that as a
|
||||
// nop.
|
||||
if (CMSIncrementalMode && _icms_start_limit != space->end()) {
|
||||
if (top <= _icms_start_limit) {
|
||||
if (CMSTraceIncrementalMode) {
|
||||
space->print_on(gclog_or_tty);
|
||||
gclog_or_tty->stamp();
|
||||
gclog_or_tty->print_cr(" start limit top=" PTR_FORMAT
|
||||
", new limit=" PTR_FORMAT
|
||||
" (" SIZE_FORMAT "%%)",
|
||||
p2i(top), p2i(_icms_stop_limit),
|
||||
percent_of_space(space, _icms_stop_limit));
|
||||
}
|
||||
ConcurrentMarkSweepThread::start_icms();
|
||||
assert(top < _icms_stop_limit, "Tautology");
|
||||
if (word_size < pointer_delta(_icms_stop_limit, top)) {
|
||||
return _icms_stop_limit;
|
||||
}
|
||||
|
||||
// The allocation will cross both the _start and _stop limits, so do the
|
||||
// stop notification also and return end().
|
||||
if (CMSTraceIncrementalMode) {
|
||||
space->print_on(gclog_or_tty);
|
||||
gclog_or_tty->stamp();
|
||||
gclog_or_tty->print_cr(" +stop limit top=" PTR_FORMAT
|
||||
", new limit=" PTR_FORMAT
|
||||
" (" SIZE_FORMAT "%%)",
|
||||
p2i(top), p2i(space->end()),
|
||||
percent_of_space(space, space->end()));
|
||||
}
|
||||
ConcurrentMarkSweepThread::stop_icms();
|
||||
return space->end();
|
||||
}
|
||||
|
||||
if (top <= _icms_stop_limit) {
|
||||
if (CMSTraceIncrementalMode) {
|
||||
space->print_on(gclog_or_tty);
|
||||
gclog_or_tty->stamp();
|
||||
gclog_or_tty->print_cr(" stop limit top=" PTR_FORMAT
|
||||
", new limit=" PTR_FORMAT
|
||||
" (" SIZE_FORMAT "%%)",
|
||||
top, space->end(),
|
||||
percent_of_space(space, space->end()));
|
||||
}
|
||||
ConcurrentMarkSweepThread::stop_icms();
|
||||
return space->end();
|
||||
}
|
||||
|
||||
if (CMSTraceIncrementalMode) {
|
||||
space->print_on(gclog_or_tty);
|
||||
gclog_or_tty->stamp();
|
||||
gclog_or_tty->print_cr(" end limit top=" PTR_FORMAT
|
||||
", new limit=" PTR_FORMAT,
|
||||
top, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) {
|
||||
assert(obj_size == (size_t)obj->size(), "bad obj_size passed in");
|
||||
// allocate, copy and if necessary update promoinfo --
|
||||
@ -1289,14 +1076,6 @@ oop ConcurrentMarkSweepGeneration::promote(oop obj, size_t obj_size) {
|
||||
}
|
||||
|
||||
|
||||
HeapWord*
|
||||
ConcurrentMarkSweepGeneration::allocation_limit_reached(Space* space,
|
||||
HeapWord* top,
|
||||
size_t word_sz)
|
||||
{
|
||||
return collector()->allocation_limit_reached(space, top, word_sz);
|
||||
}
|
||||
|
||||
// IMPORTANT: Notes on object size recognition in CMS.
|
||||
// ---------------------------------------------------
|
||||
// A block of storage in the CMS generation is always in
|
||||
@ -1809,9 +1588,6 @@ void CMSCollector::acquire_control_and_collect(bool full,
|
||||
// we want to do a foreground collection.
|
||||
_foregroundGCIsActive = true;
|
||||
|
||||
// Disable incremental mode during a foreground collection.
|
||||
ICMSDisabler icms_disabler;
|
||||
|
||||
// release locks and wait for a notify from the background collector
|
||||
// releasing the locks in only necessary for phases which
|
||||
// do yields to improve the granularity of the collection.
|
||||
@ -2135,7 +1911,7 @@ void CMSCollector::do_mark_sweep_work(bool clear_all_soft_refs,
|
||||
|
||||
void CMSCollector::print_eden_and_survivor_chunk_arrays() {
|
||||
DefNewGeneration* dng = _young_gen->as_DefNewGeneration();
|
||||
EdenSpace* eden_space = dng->eden();
|
||||
ContiguousSpace* eden_space = dng->eden();
|
||||
ContiguousSpace* from_space = dng->from();
|
||||
ContiguousSpace* to_space = dng->to();
|
||||
// Eden
|
||||
@ -2783,10 +2559,6 @@ void CMSCollector::gc_epilogue(bool full) {
|
||||
//
|
||||
_cmsGen->update_counters(cms_used);
|
||||
|
||||
if (CMSIncrementalMode) {
|
||||
icms_update_allocation_limits();
|
||||
}
|
||||
|
||||
bitMapLock()->unlock();
|
||||
releaseFreelistLocks();
|
||||
|
||||
@ -4272,12 +4044,10 @@ void CMSConcMarkingTask::coordinator_yield() {
|
||||
assert_lock_strong(_bit_map_lock);
|
||||
_bit_map_lock->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// It is possible for whichever thread initiated the yield request
|
||||
// not to get a chance to wake up and take the bitmap lock between
|
||||
@ -4307,7 +4077,6 @@ void CMSConcMarkingTask::coordinator_yield() {
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -5238,7 +5007,7 @@ class RemarkKlassClosure : public KlassClosure {
|
||||
|
||||
void CMSParMarkTask::work_on_young_gen_roots(uint worker_id, OopsInGenClosure* cl) {
|
||||
DefNewGeneration* dng = _collector->_young_gen->as_DefNewGeneration();
|
||||
EdenSpace* eden_space = dng->eden();
|
||||
ContiguousSpace* eden_space = dng->eden();
|
||||
ContiguousSpace* from_space = dng->from();
|
||||
ContiguousSpace* to_space = dng->to();
|
||||
|
||||
@ -5410,7 +5179,7 @@ CMSParMarkTask::do_young_space_rescan(uint worker_id,
|
||||
while (!pst->is_task_claimed(/* reference */ nth_task)) {
|
||||
// We claimed task # nth_task; compute its boundaries.
|
||||
if (chunk_top == 0) { // no samples were taken
|
||||
assert(nth_task == 0 && n_tasks == 1, "Can have only 1 EdenSpace task");
|
||||
assert(nth_task == 0 && n_tasks == 1, "Can have only 1 eden task");
|
||||
start = space->bottom();
|
||||
end = space->top();
|
||||
} else if (nth_task == 0) {
|
||||
@ -5788,7 +5557,7 @@ void CMSCollector::do_remark_parallel() {
|
||||
// process_roots (which currently doesn't know how to
|
||||
// parallelize such a scan), but rather will be broken up into
|
||||
// a set of parallel tasks (via the sampling that the [abortable]
|
||||
// preclean phase did of EdenSpace, plus the [two] tasks of
|
||||
// preclean phase did of eden, plus the [two] tasks of
|
||||
// scanning the [two] survivor spaces. Further fine-grain
|
||||
// parallelization of the scanning of the survivor spaces
|
||||
// themselves, and of precleaning of the younger gen itself
|
||||
@ -6474,19 +6243,16 @@ void CMSCollector::reset(bool asynch) {
|
||||
assert_lock_strong(bitMapLock());
|
||||
bitMapLock()->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
incrementYields();
|
||||
}
|
||||
icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -6509,10 +6275,6 @@ void CMSCollector::reset(bool asynch) {
|
||||
_collectorState = Idling;
|
||||
}
|
||||
|
||||
// Stop incremental mode after a cycle completes, so that any future cycles
|
||||
// are triggered by allocation.
|
||||
stop_icms();
|
||||
|
||||
NOT_PRODUCT(
|
||||
if (RotateCMSCollectionTypes) {
|
||||
_cmsGen->rotate_debug_collection_type();
|
||||
@ -6964,12 +6726,10 @@ void MarkRefsIntoAndScanClosure::do_yield_work() {
|
||||
_bit_map->lock()->unlock();
|
||||
_freelistLock->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0;
|
||||
@ -6978,7 +6738,6 @@ void MarkRefsIntoAndScanClosure::do_yield_work() {
|
||||
!CMSCollector::foregroundGCIsActive();
|
||||
++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -7124,19 +6883,16 @@ void ScanMarkedObjectsAgainCarefullyClosure::do_yield_work() {
|
||||
_bitMap->lock()->unlock();
|
||||
_freelistLock->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -7196,19 +6952,16 @@ void SurvivorSpacePrecleanClosure::do_yield_work() {
|
||||
// Relinquish the bit map lock
|
||||
_bit_map->lock()->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -7354,19 +7107,16 @@ void MarkFromRootsClosure::do_yield_work() {
|
||||
assert_lock_strong(_bitMap->lock());
|
||||
_bitMap->lock()->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -7388,7 +7138,7 @@ void MarkFromRootsClosure::scanOopsInOop(HeapWord* ptr) {
|
||||
_finger = ptr + obj->size();
|
||||
assert(_finger > ptr, "we just incremented it above");
|
||||
// On large heaps, it may take us some time to get through
|
||||
// the marking phase (especially if running iCMS). During
|
||||
// the marking phase. During
|
||||
// this time it's possible that a lot of mutations have
|
||||
// accumulated in the card table and the mod union table --
|
||||
// these mutation records are redundant until we have
|
||||
@ -7505,7 +7255,7 @@ void Par_MarkFromRootsClosure::scan_oops_in_oop(HeapWord* ptr) {
|
||||
_finger = ptr + obj->size();
|
||||
assert(_finger > ptr, "we just incremented it above");
|
||||
// On large heaps, it may take us some time to get through
|
||||
// the marking phase (especially if running iCMS). During
|
||||
// the marking phase. During
|
||||
// this time it's possible that a lot of mutations have
|
||||
// accumulated in the card table and the mod union table --
|
||||
// these mutation records are redundant until we have
|
||||
@ -7994,20 +7744,16 @@ void CMSPrecleanRefsYieldClosure::do_yield_work() {
|
||||
bml->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
@ -8675,19 +8421,16 @@ void SweepClosure::do_yield_work(HeapWord* addr) {
|
||||
_bitMap->lock()->unlock();
|
||||
_freelistLock->unlock();
|
||||
ConcurrentMarkSweepThread::desynchronize(true);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
_collector->stopTimer();
|
||||
if (PrintCMSStatistics != 0) {
|
||||
_collector->incrementYields();
|
||||
}
|
||||
_collector->icms_wait();
|
||||
|
||||
// See the comment in coordinator_yield()
|
||||
for (unsigned i = 0; i < CMSYieldSleepCount &&
|
||||
ConcurrentMarkSweepThread::should_yield() &&
|
||||
!CMSCollector::foregroundGCIsActive(); ++i) {
|
||||
os::sleep(Thread::current(), 1, false);
|
||||
ConcurrentMarkSweepThread::acknowledge_yield_request();
|
||||
}
|
||||
|
||||
ConcurrentMarkSweepThread::synchronize(true);
|
||||
|
@ -356,7 +356,6 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
size_t _gc0_promoted; // bytes promoted per gc0
|
||||
double _cms_duration;
|
||||
double _cms_duration_pre_sweep; // time from initiation to start of sweep
|
||||
double _cms_duration_per_mb;
|
||||
double _cms_period;
|
||||
size_t _cms_allocated; // bytes of direct allocation per gc0 period
|
||||
|
||||
@ -383,17 +382,7 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
unsigned int _valid_bits;
|
||||
|
||||
unsigned int _icms_duty_cycle; // icms duty cycle (0-100).
|
||||
|
||||
protected:
|
||||
|
||||
// Return a duty cycle that avoids wild oscillations, by limiting the amount
|
||||
// of change between old_duty_cycle and new_duty_cycle (the latter is treated
|
||||
// as a recommended value).
|
||||
static unsigned int icms_damped_duty_cycle(unsigned int old_duty_cycle,
|
||||
unsigned int new_duty_cycle);
|
||||
unsigned int icms_update_duty_cycle_impl();
|
||||
|
||||
// In support of adjusting of cms trigger ratios based on history
|
||||
// of concurrent mode failure.
|
||||
double cms_free_adjustment_factor(size_t free) const;
|
||||
@ -426,7 +415,6 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
size_t gc0_promoted() const { return _gc0_promoted; }
|
||||
double cms_period() const { return _cms_period; }
|
||||
double cms_duration() const { return _cms_duration; }
|
||||
double cms_duration_per_mb() const { return _cms_duration_per_mb; }
|
||||
size_t cms_allocated() const { return _cms_allocated; }
|
||||
|
||||
size_t cms_used_at_gc0_end() const { return _cms_used_at_gc0_end;}
|
||||
@ -458,12 +446,6 @@ class CMSStats VALUE_OBJ_CLASS_SPEC {
|
||||
|
||||
// End of higher level statistics.
|
||||
|
||||
// Returns the cms incremental mode duty cycle, as a percentage (0-100).
|
||||
unsigned int icms_duty_cycle() const { return _icms_duty_cycle; }
|
||||
|
||||
// Update the duty cycle and return the new value.
|
||||
unsigned int icms_update_duty_cycle();
|
||||
|
||||
// Debugging.
|
||||
void print_on(outputStream* st) const PRODUCT_RETURN;
|
||||
void print() const { print_on(gclog_or_tty); }
|
||||
@ -725,13 +707,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
// Timing, allocation and promotion statistics, used for scheduling.
|
||||
CMSStats _stats;
|
||||
|
||||
// Allocation limits installed in the young gen, used only in
|
||||
// CMSIncrementalMode. When an allocation in the young gen would cross one of
|
||||
// these limits, the cms generation is notified and the cms thread is started
|
||||
// or stopped, respectively.
|
||||
HeapWord* _icms_start_limit;
|
||||
HeapWord* _icms_stop_limit;
|
||||
|
||||
enum CMS_op_type {
|
||||
CMS_op_checkpointRootsInitial,
|
||||
CMS_op_checkpointRootsFinal
|
||||
@ -867,10 +842,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
// collector.
|
||||
bool waitForForegroundGC();
|
||||
|
||||
// Incremental mode triggering: recompute the icms duty cycle and set the
|
||||
// allocation limits in the young gen.
|
||||
void icms_update_allocation_limits();
|
||||
|
||||
size_t block_size_using_printezis_bits(HeapWord* addr) const;
|
||||
size_t block_size_if_printezis_bits(HeapWord* addr) const;
|
||||
HeapWord* next_card_start_after_block(HeapWord* addr) const;
|
||||
@ -928,9 +899,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
void promoted(bool par, HeapWord* start,
|
||||
bool is_obj_array, size_t obj_size);
|
||||
|
||||
HeapWord* allocation_limit_reached(Space* space, HeapWord* top,
|
||||
size_t word_size);
|
||||
|
||||
void getFreelistLocks() const;
|
||||
void releaseFreelistLocks() const;
|
||||
bool haveFreelistLocks() const;
|
||||
@ -1001,14 +969,6 @@ class CMSCollector: public CHeapObj<mtGC> {
|
||||
// Timers/stats for gc scheduling and incremental mode pacing.
|
||||
CMSStats& stats() { return _stats; }
|
||||
|
||||
// Convenience methods that check whether CMSIncrementalMode is enabled and
|
||||
// forward to the corresponding methods in ConcurrentMarkSweepThread.
|
||||
static void start_icms();
|
||||
static void stop_icms(); // Called at the end of the cms cycle.
|
||||
static void disable_icms(); // Called before a foreground collection.
|
||||
static void enable_icms(); // Called after a foreground collection.
|
||||
void icms_wait(); // Called at yield points.
|
||||
|
||||
// Adaptive size policy
|
||||
AdaptiveSizePolicy* size_policy();
|
||||
|
||||
@ -1211,9 +1171,6 @@ class ConcurrentMarkSweepGeneration: public CardGeneration {
|
||||
return allocate(size, tlab);
|
||||
}
|
||||
|
||||
// Incremental mode triggering.
|
||||
HeapWord* allocation_limit_reached(Space* space, HeapWord* top,
|
||||
size_t word_size);
|
||||
|
||||
// Used by CMSStats to track direct allocation. The value is sampled and
|
||||
// reset after each young gen collection.
|
||||
|
@ -234,36 +234,6 @@ inline void CMSBitMap::iterate(BitMapClosure* cl, HeapWord* left,
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::start_icms() {
|
||||
if (CMSIncrementalMode) {
|
||||
ConcurrentMarkSweepThread::start_icms();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::stop_icms() {
|
||||
if (CMSIncrementalMode) {
|
||||
ConcurrentMarkSweepThread::stop_icms();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::disable_icms() {
|
||||
if (CMSIncrementalMode) {
|
||||
ConcurrentMarkSweepThread::disable_icms();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::enable_icms() {
|
||||
if (CMSIncrementalMode) {
|
||||
ConcurrentMarkSweepThread::enable_icms();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::icms_wait() {
|
||||
if (CMSIncrementalMode) {
|
||||
cmsThread()->icms_wait();
|
||||
}
|
||||
}
|
||||
|
||||
inline void CMSCollector::save_sweep_limits() {
|
||||
_cmsGen->save_sweep_limit();
|
||||
}
|
||||
@ -363,12 +333,6 @@ inline void CMSStats::record_cms_end() {
|
||||
_cms_duration = AdaptiveWeightedAverage::exp_avg(_cms_duration,
|
||||
cur_duration, _cms_alpha);
|
||||
|
||||
// Avoid division by 0.
|
||||
const size_t cms_used_mb = MAX2(_cms_used_at_cms_begin / M, (size_t)1);
|
||||
_cms_duration_per_mb = AdaptiveWeightedAverage::exp_avg(_cms_duration_per_mb,
|
||||
cur_duration / cms_used_mb,
|
||||
_cms_alpha);
|
||||
|
||||
_cms_end_time.update();
|
||||
_cms_alpha = _saved_alpha;
|
||||
_allow_duty_cycle_reduction = true;
|
||||
@ -400,15 +364,6 @@ inline double CMSStats::cms_consumption_rate() const {
|
||||
return (gc0_promoted() + cms_allocated()) / gc0_period();
|
||||
}
|
||||
|
||||
inline unsigned int CMSStats::icms_update_duty_cycle() {
|
||||
// Update the duty cycle only if pacing is enabled and the stats are valid
|
||||
// (after at least one young gen gc and one cms cycle have completed).
|
||||
if (CMSIncrementalPacing && valid()) {
|
||||
return icms_update_duty_cycle_impl();
|
||||
}
|
||||
return _icms_duty_cycle;
|
||||
}
|
||||
|
||||
inline void ConcurrentMarkSweepGeneration::save_sweep_limit() {
|
||||
cmsSpace()->save_sweep_limit();
|
||||
}
|
||||
|
@ -49,13 +49,6 @@ bool ConcurrentMarkSweepThread::_should_terminate = false;
|
||||
int ConcurrentMarkSweepThread::_CMS_flag = CMS_nil;
|
||||
|
||||
volatile jint ConcurrentMarkSweepThread::_pending_yields = 0;
|
||||
volatile jint ConcurrentMarkSweepThread::_pending_decrements = 0;
|
||||
|
||||
volatile jint ConcurrentMarkSweepThread::_icms_disabled = 0;
|
||||
volatile bool ConcurrentMarkSweepThread::_should_run = false;
|
||||
// When icms is enabled, the icms thread is stopped until explicitly
|
||||
// started.
|
||||
volatile bool ConcurrentMarkSweepThread::_should_stop = true;
|
||||
|
||||
SurrogateLockerThread*
|
||||
ConcurrentMarkSweepThread::_slt = NULL;
|
||||
@ -99,7 +92,6 @@ ConcurrentMarkSweepThread::ConcurrentMarkSweepThread(CMSCollector* collector)
|
||||
}
|
||||
}
|
||||
_sltMonitor = SLT_lock;
|
||||
assert(!CMSIncrementalMode || icms_is_enabled(), "Error");
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepThread::run() {
|
||||
@ -184,11 +176,6 @@ ConcurrentMarkSweepThread* ConcurrentMarkSweepThread::start(CMSCollector* collec
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepThread::stop() {
|
||||
if (CMSIncrementalMode) {
|
||||
// Disable incremental mode and wake up the thread so it notices the change.
|
||||
disable_icms();
|
||||
start_icms();
|
||||
}
|
||||
// it is ok to take late safepoints here, if needed
|
||||
{
|
||||
MutexLockerEx x(Terminator_lock);
|
||||
@ -387,23 +374,13 @@ void ConcurrentMarkSweepThread::wait_on_cms_lock_for_scavenge(long t_millis) {
|
||||
|
||||
void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
|
||||
while (!_should_terminate) {
|
||||
if (CMSIncrementalMode) {
|
||||
icms_wait();
|
||||
if(CMSWaitDuration >= 0) {
|
||||
// Wait until the next synchronous GC, a concurrent full gc
|
||||
// request or a timeout, whichever is earlier.
|
||||
wait_on_cms_lock_for_scavenge(CMSWaitDuration);
|
||||
}
|
||||
return;
|
||||
if(CMSWaitDuration >= 0) {
|
||||
// Wait until the next synchronous GC, a concurrent full gc
|
||||
// request or a timeout, whichever is earlier.
|
||||
wait_on_cms_lock_for_scavenge(CMSWaitDuration);
|
||||
} else {
|
||||
if(CMSWaitDuration >= 0) {
|
||||
// Wait until the next synchronous GC, a concurrent full gc
|
||||
// request or a timeout, whichever is earlier.
|
||||
wait_on_cms_lock_for_scavenge(CMSWaitDuration);
|
||||
} else {
|
||||
// Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently
|
||||
wait_on_cms_lock(CMSCheckInterval);
|
||||
}
|
||||
// Wait until any cms_lock event or check interval not to call shouldConcurrentCollect permanently
|
||||
wait_on_cms_lock(CMSCheckInterval);
|
||||
}
|
||||
// Check if we should start a CMS collection cycle
|
||||
if (_collector->shouldConcurrentCollect()) {
|
||||
@ -414,42 +391,6 @@ void ConcurrentMarkSweepThread::sleepBeforeNextCycle() {
|
||||
}
|
||||
}
|
||||
|
||||
// Incremental CMS
|
||||
void ConcurrentMarkSweepThread::start_icms() {
|
||||
assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
|
||||
MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
|
||||
trace_state("start_icms");
|
||||
_should_run = true;
|
||||
iCMS_lock->notify_all();
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepThread::stop_icms() {
|
||||
assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
|
||||
MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
|
||||
if (!_should_stop) {
|
||||
trace_state("stop_icms");
|
||||
_should_stop = true;
|
||||
_should_run = false;
|
||||
asynchronous_yield_request();
|
||||
iCMS_lock->notify_all();
|
||||
}
|
||||
}
|
||||
|
||||
void ConcurrentMarkSweepThread::icms_wait() {
|
||||
assert(UseConcMarkSweepGC && CMSIncrementalMode, "just checking");
|
||||
if (_should_stop && icms_is_enabled()) {
|
||||
MutexLockerEx x(iCMS_lock, Mutex::_no_safepoint_check_flag);
|
||||
trace_state("pause_icms");
|
||||
_collector->stats().stop_cms_timer();
|
||||
while(!_should_run && icms_is_enabled()) {
|
||||
iCMS_lock->wait(Mutex::_no_safepoint_check_flag);
|
||||
}
|
||||
_collector->stats().start_cms_timer();
|
||||
_should_stop = false;
|
||||
trace_state("pause_icms end");
|
||||
}
|
||||
}
|
||||
|
||||
// Note: this method, although exported by the ConcurrentMarkSweepThread,
|
||||
// which is a non-JavaThread, can only be called by a JavaThread.
|
||||
// Currently this is done at vm creation time (post-vm-init) by the
|
||||
|
@ -64,20 +64,11 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
|
||||
static bool clear_CMS_flag(int b) { return (_CMS_flag &= ~b) != 0; }
|
||||
void sleepBeforeNextCycle();
|
||||
|
||||
// CMS thread should yield for a young gen collection, direct allocation,
|
||||
// and iCMS activity.
|
||||
// CMS thread should yield for a young gen collection and direct allocations
|
||||
static char _pad_1[64 - sizeof(jint)]; // prevent cache-line sharing
|
||||
static volatile jint _pending_yields;
|
||||
static volatile jint _pending_decrements; // decrements to _pending_yields
|
||||
static char _pad_2[64 - sizeof(jint)]; // prevent cache-line sharing
|
||||
|
||||
// Tracing messages, enabled by CMSTraceThreadState.
|
||||
static inline void trace_state(const char* desc);
|
||||
|
||||
static volatile int _icms_disabled; // a counter to track #iCMS disable & enable
|
||||
static volatile bool _should_run; // iCMS may run
|
||||
static volatile bool _should_stop; // iCMS should stop
|
||||
|
||||
// debugging
|
||||
void verify_ok_to_terminate() const PRODUCT_RETURN;
|
||||
|
||||
@ -135,44 +126,13 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
|
||||
void wait_on_cms_lock_for_scavenge(long t_millis);
|
||||
|
||||
// The CMS thread will yield during the work portion of its cycle
|
||||
// only when requested to. Both synchronous and asychronous requests
|
||||
// are provided:
|
||||
// (1) A synchronous request is used for young gen collections and
|
||||
// for direct allocations. The requesting thread increments
|
||||
// _pending_yields at the beginning of an operation, and decrements
|
||||
// _pending_yields when that operation is completed.
|
||||
// In turn, the CMS thread yields when _pending_yields is positive,
|
||||
// and continues to yield until the value reverts to 0.
|
||||
// (2) An asynchronous request, on the other hand, is used by iCMS
|
||||
// for the stop_icms() operation. A single yield satisfies all of
|
||||
// the outstanding asynch yield requests, of which there may
|
||||
// occasionally be several in close succession. To accomplish
|
||||
// this, an asynch-requesting thread atomically increments both
|
||||
// _pending_yields and _pending_decrements. An asynchr requesting
|
||||
// thread does not wait and "acknowledge" completion of an operation
|
||||
// and deregister the request, like the synchronous version described
|
||||
// above does. In turn, after yielding, the CMS thread decrements both
|
||||
// _pending_yields and _pending_decrements by the value seen in
|
||||
// _pending_decrements before the decrement.
|
||||
// NOTE: The above scheme is isomorphic to having two request counters,
|
||||
// one for async requests and one for sync requests, and for the CMS thread
|
||||
// to check the sum of the two counters to decide whether it should yield
|
||||
// and to clear only the async counter when it yields. However, it turns out
|
||||
// to be more efficient for CMS code to just check a single counter
|
||||
// _pending_yields that holds the sum (of both sync and async requests), and
|
||||
// a second counter _pending_decrements that only holds the async requests,
|
||||
// for greater efficiency, since in a typical CMS run, there are many more
|
||||
// potential (i.e. static) yield points than there are actual
|
||||
// (i.e. dynamic) yields because of requests, which are few and far between.
|
||||
//
|
||||
// Note that, while "_pending_yields >= _pending_decrements" is an invariant,
|
||||
// we cannot easily test that invariant, since the counters are manipulated via
|
||||
// atomic instructions without explicit locking and we cannot read
|
||||
// the two counters atomically together: one suggestion is to
|
||||
// use (for example) 16-bit counters so as to be able to read the
|
||||
// two counters atomically even on 32-bit platforms. Notice that
|
||||
// the second assert in acknowledge_yield_request() below does indeed
|
||||
// check a form of the above invariant, albeit indirectly.
|
||||
// only when requested to.
|
||||
// A synchronous request is used for young gen collections and
|
||||
// for direct allocations. The requesting thread increments
|
||||
// _pending_yields at the beginning of an operation, and decrements
|
||||
// _pending_yields when that operation is completed.
|
||||
// In turn, the CMS thread yields when _pending_yields is positive,
|
||||
// and continues to yield until the value reverts to 0.
|
||||
|
||||
static void increment_pending_yields() {
|
||||
Atomic::inc(&_pending_yields);
|
||||
@ -182,67 +142,9 @@ class ConcurrentMarkSweepThread: public ConcurrentGCThread {
|
||||
Atomic::dec(&_pending_yields);
|
||||
assert(_pending_yields >= 0, "can't be negative");
|
||||
}
|
||||
static void asynchronous_yield_request() {
|
||||
assert(CMSIncrementalMode, "Currently only used w/iCMS");
|
||||
increment_pending_yields();
|
||||
Atomic::inc(&_pending_decrements);
|
||||
assert(_pending_decrements >= 0, "can't be negative");
|
||||
}
|
||||
static void acknowledge_yield_request() {
|
||||
jint decrement = _pending_decrements;
|
||||
if (decrement > 0) {
|
||||
assert(CMSIncrementalMode, "Currently only used w/iCMS");
|
||||
// Order important to preserve: _pending_yields >= _pending_decrements
|
||||
Atomic::add(-decrement, &_pending_decrements);
|
||||
Atomic::add(-decrement, &_pending_yields);
|
||||
assert(_pending_decrements >= 0, "can't be negative");
|
||||
assert(_pending_yields >= 0, "can't be negative");
|
||||
}
|
||||
}
|
||||
static bool should_yield() { return _pending_yields > 0; }
|
||||
|
||||
// CMS incremental mode.
|
||||
static void start_icms(); // notify thread to start a quantum of work
|
||||
static void stop_icms(); // request thread to stop working
|
||||
void icms_wait(); // if asked to stop, wait until notified to start
|
||||
|
||||
// Incremental mode is enabled globally by the flag CMSIncrementalMode. It
|
||||
// must also be enabled/disabled dynamically to allow foreground collections.
|
||||
#define ICMS_ENABLING_ASSERT \
|
||||
assert((CMSIncrementalMode && _icms_disabled >= 0) || \
|
||||
(!CMSIncrementalMode && _icms_disabled <= 0), "Error")
|
||||
|
||||
static inline void enable_icms() {
|
||||
ICMS_ENABLING_ASSERT;
|
||||
Atomic::dec(&_icms_disabled);
|
||||
}
|
||||
static inline void disable_icms() {
|
||||
ICMS_ENABLING_ASSERT;
|
||||
Atomic::inc(&_icms_disabled);
|
||||
}
|
||||
static inline bool icms_is_disabled() {
|
||||
ICMS_ENABLING_ASSERT;
|
||||
return _icms_disabled > 0;
|
||||
}
|
||||
static inline bool icms_is_enabled() {
|
||||
return !icms_is_disabled();
|
||||
}
|
||||
};
|
||||
|
||||
inline void ConcurrentMarkSweepThread::trace_state(const char* desc) {
|
||||
if (CMSTraceThreadState) {
|
||||
char buf[128];
|
||||
TimeStamp& ts = gclog_or_tty->time_stamp();
|
||||
if (!ts.is_updated()) {
|
||||
ts.update();
|
||||
}
|
||||
jio_snprintf(buf, sizeof(buf), " [%.3f: CMSThread %s] ",
|
||||
ts.seconds(), desc);
|
||||
buf[sizeof(buf) - 1] = '\0';
|
||||
gclog_or_tty->print("%s", buf);
|
||||
}
|
||||
}
|
||||
|
||||
// For scoped increment/decrement of (synchronous) yield requests
|
||||
class CMSSynchronousYieldRequest: public StackObj {
|
||||
public:
|
||||
|
@ -207,12 +207,6 @@ void VM_GenCollectFullConcurrent::doit() {
|
||||
MutexLockerEx x(FullGCCount_lock, Mutex::_no_safepoint_check_flag);
|
||||
assert(_full_gc_count_before <= gch->total_full_collections(), "Error");
|
||||
if (gch->total_full_collections() == _full_gc_count_before) {
|
||||
// Disable iCMS until the full collection is done, and
|
||||
// remember that we did so.
|
||||
CMSCollector::disable_icms();
|
||||
_disabled_icms = true;
|
||||
// In case CMS thread was in icms_wait(), wake it up.
|
||||
CMSCollector::start_icms();
|
||||
// Nudge the CMS thread to start a concurrent collection.
|
||||
CMSCollector::request_full_gc(_full_gc_count_before, _gc_cause);
|
||||
} else {
|
||||
@ -276,8 +270,4 @@ void VM_GenCollectFullConcurrent::doit_epilogue() {
|
||||
FullGCCount_lock->wait(Mutex::_no_safepoint_check_flag);
|
||||
}
|
||||
}
|
||||
// Enable iCMS back if we disabled it earlier.
|
||||
if (_disabled_icms) {
|
||||
CMSCollector::enable_icms();
|
||||
}
|
||||
}
|
||||
|
@ -128,13 +128,11 @@ class VM_CMS_Final_Remark: public VM_CMS_Operation {
|
||||
// VM operation to invoke a concurrent collection of the heap as a
|
||||
// GenCollectedHeap heap.
|
||||
class VM_GenCollectFullConcurrent: public VM_GC_Operation {
|
||||
bool _disabled_icms;
|
||||
public:
|
||||
VM_GenCollectFullConcurrent(unsigned int gc_count_before,
|
||||
unsigned int full_gc_count_before,
|
||||
GCCause::Cause gc_cause)
|
||||
: VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */),
|
||||
_disabled_icms(false)
|
||||
: VM_GC_Operation(gc_count_before, gc_cause, full_gc_count_before, true /* full */)
|
||||
{
|
||||
assert(FullGCCount_lock != NULL, "Error");
|
||||
assert(UseAsyncConcMarkSweepGC, "Else will hang caller");
|
||||
|
@ -180,9 +180,32 @@ class ClearBitmapHRClosure : public HeapRegionClosure {
|
||||
}
|
||||
};
|
||||
|
||||
class ParClearNextMarkBitmapTask : public AbstractGangTask {
|
||||
ClearBitmapHRClosure* _cl;
|
||||
HeapRegionClaimer _hrclaimer;
|
||||
bool _suspendible; // If the task is suspendible, workers must join the STS.
|
||||
|
||||
public:
|
||||
ParClearNextMarkBitmapTask(ClearBitmapHRClosure *cl, uint n_workers, bool suspendible) :
|
||||
_cl(cl), _suspendible(suspendible), AbstractGangTask("Parallel Clear Bitmap Task"), _hrclaimer(n_workers) {}
|
||||
|
||||
void work(uint worker_id) {
|
||||
if (_suspendible) {
|
||||
SuspendibleThreadSet::join();
|
||||
}
|
||||
G1CollectedHeap::heap()->heap_region_par_iterate(_cl, worker_id, &_hrclaimer);
|
||||
if (_suspendible) {
|
||||
SuspendibleThreadSet::leave();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void CMBitMap::clearAll() {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
ClearBitmapHRClosure cl(NULL, this, false /* may_yield */);
|
||||
G1CollectedHeap::heap()->heap_region_iterate(&cl);
|
||||
uint n_workers = g1h->workers()->active_workers();
|
||||
ParClearNextMarkBitmapTask task(&cl, n_workers, false);
|
||||
g1h->workers()->run_task(&task);
|
||||
guarantee(cl.complete(), "Must have completed iteration.");
|
||||
return;
|
||||
}
|
||||
@ -861,7 +884,8 @@ void ConcurrentMark::clearNextBitmap() {
|
||||
guarantee(!g1h->mark_in_progress(), "invariant");
|
||||
|
||||
ClearBitmapHRClosure cl(this, _nextMarkBitMap, true /* may_yield */);
|
||||
g1h->heap_region_iterate(&cl);
|
||||
ParClearNextMarkBitmapTask task(&cl, parallel_marking_threads(), true);
|
||||
_parallel_workers->run_task(&task);
|
||||
|
||||
// Clear the liveness counting data. If the marking has been aborted, the abort()
|
||||
// call already did that.
|
||||
|
@ -280,7 +280,6 @@ void ConcurrentMarkThread::run() {
|
||||
// We may have aborted just before the remark. Do not bother clearing the
|
||||
// bitmap then, as it has been done during mark abort.
|
||||
if (!cm()->has_aborted()) {
|
||||
SuspendibleThreadSetJoiner sts;
|
||||
_cm->clearNextBitmap();
|
||||
} else {
|
||||
assert(!G1VerifyBitmaps || _cm->nextMarkBitmapIsClear(), "Next mark bitmap must be clear");
|
||||
|
@ -1248,7 +1248,7 @@ public:
|
||||
// The same as above but assume that the caller holds the Heap_lock.
|
||||
void collect_locked(GCCause::Cause cause);
|
||||
|
||||
virtual void copy_allocation_context_stats(const jint* contexts,
|
||||
virtual bool copy_allocation_context_stats(const jint* contexts,
|
||||
jlong* totals,
|
||||
jbyte* accuracy,
|
||||
jint len);
|
||||
|
@ -25,8 +25,9 @@
|
||||
#include "precompiled.hpp"
|
||||
#include "gc_implementation/g1/g1CollectedHeap.hpp"
|
||||
|
||||
void G1CollectedHeap::copy_allocation_context_stats(const jint* contexts,
|
||||
bool G1CollectedHeap::copy_allocation_context_stats(const jint* contexts,
|
||||
jlong* totals,
|
||||
jbyte* accuracy,
|
||||
jint len) {
|
||||
return false;
|
||||
}
|
||||
|
@ -1585,34 +1585,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
uint G1CollectorPolicy::calculate_parallel_work_chunk_size(uint n_workers, uint n_regions) {
|
||||
assert(n_workers > 0, "Active gc workers should be greater than 0");
|
||||
const uint overpartition_factor = 4;
|
||||
const uint min_chunk_size = MAX2(n_regions / n_workers, 1U);
|
||||
return MAX2(n_regions / (n_workers * overpartition_factor), min_chunk_size);
|
||||
}
|
||||
|
||||
void
|
||||
G1CollectorPolicy::record_concurrent_mark_cleanup_end(int no_of_gc_threads) {
|
||||
G1CollectorPolicy::record_concurrent_mark_cleanup_end(uint n_workers) {
|
||||
_collectionSetChooser->clear();
|
||||
|
||||
uint region_num = _g1->num_regions();
|
||||
const uint OverpartitionFactor = 4;
|
||||
uint WorkUnit;
|
||||
// The use of MinChunkSize = 8 in the original code
|
||||
// causes some assertion failures when the total number of
|
||||
// region is less than 8. The code here tries to fix that.
|
||||
// Should the original code also be fixed?
|
||||
if (no_of_gc_threads > 0) {
|
||||
const uint MinWorkUnit = MAX2(region_num / no_of_gc_threads, 1U);
|
||||
WorkUnit = MAX2(region_num / (no_of_gc_threads * OverpartitionFactor),
|
||||
MinWorkUnit);
|
||||
} else {
|
||||
assert(no_of_gc_threads > 0,
|
||||
"The active gc workers should be greater than 0");
|
||||
// In a product build do something reasonable to avoid a crash.
|
||||
const uint MinWorkUnit = MAX2(region_num / (uint) ParallelGCThreads, 1U);
|
||||
WorkUnit =
|
||||
MAX2(region_num / (uint) (ParallelGCThreads * OverpartitionFactor),
|
||||
MinWorkUnit);
|
||||
}
|
||||
_collectionSetChooser->prepare_for_par_region_addition(_g1->num_regions(),
|
||||
WorkUnit);
|
||||
ParKnownGarbageTask parKnownGarbageTask(_collectionSetChooser, WorkUnit, (uint) no_of_gc_threads);
|
||||
_g1->workers()->run_task(&parKnownGarbageTask);
|
||||
uint n_regions = _g1->num_regions();
|
||||
uint chunk_size = calculate_parallel_work_chunk_size(n_workers, n_regions);
|
||||
_collectionSetChooser->prepare_for_par_region_addition(n_regions, chunk_size);
|
||||
ParKnownGarbageTask par_known_garbage_task(_collectionSetChooser, chunk_size, n_workers);
|
||||
_g1->workers()->run_task(&par_known_garbage_task);
|
||||
|
||||
_collectionSetChooser->sort_regions();
|
||||
|
||||
|
@ -612,6 +612,10 @@ private:
|
||||
uint desired_min_length,
|
||||
uint desired_max_length);
|
||||
|
||||
// Calculate and return chunk size (in number of regions) for parallel
|
||||
// concurrent mark cleanup.
|
||||
uint calculate_parallel_work_chunk_size(uint n_workers, uint n_regions);
|
||||
|
||||
// Check whether a given young length (young_length) fits into the
|
||||
// given target pause time and whether the prediction for the amount
|
||||
// of objects to be copied for the given length will fit into the
|
||||
@ -687,7 +691,7 @@ public:
|
||||
|
||||
// Record start, end, and completion of cleanup.
|
||||
void record_concurrent_mark_cleanup_start();
|
||||
void record_concurrent_mark_cleanup_end(int no_of_gc_threads);
|
||||
void record_concurrent_mark_cleanup_end(uint n_workers);
|
||||
void record_concurrent_mark_cleanup_completed();
|
||||
|
||||
// Records the information about the heap size for reporting in
|
||||
|
@ -960,6 +960,10 @@ void HeapRegion::verify() const {
|
||||
verify(VerifyOption_G1UsePrevMarking, /* failures */ &dummy);
|
||||
}
|
||||
|
||||
void HeapRegion::prepare_for_compaction(CompactPoint* cp) {
|
||||
scan_and_forward(this, cp);
|
||||
}
|
||||
|
||||
// G1OffsetTableContigSpace code; copied from space.cpp. Hope this can go
|
||||
// away eventually.
|
||||
|
||||
@ -1043,12 +1047,6 @@ void G1OffsetTableContigSpace::object_iterate(ObjectClosure* blk) {
|
||||
}
|
||||
}
|
||||
|
||||
#define block_is_always_obj(q) true
|
||||
void G1OffsetTableContigSpace::prepare_for_compaction(CompactPoint* cp) {
|
||||
SCAN_AND_FORWARD(cp, top, block_is_always_obj, block_size);
|
||||
}
|
||||
#undef block_is_always_obj
|
||||
|
||||
G1OffsetTableContigSpace::
|
||||
G1OffsetTableContigSpace(G1BlockOffsetSharedArray* sharedOffsetArray,
|
||||
MemRegion mr) :
|
||||
|
@ -187,8 +187,6 @@ class G1OffsetTableContigSpace: public CompactibleSpace {
|
||||
HeapWord* block_start(const void* p);
|
||||
HeapWord* block_start_const(const void* p) const;
|
||||
|
||||
void prepare_for_compaction(CompactPoint* cp);
|
||||
|
||||
// Add offset table update.
|
||||
virtual HeapWord* allocate(size_t word_size);
|
||||
HeapWord* par_allocate(size_t word_size);
|
||||
@ -210,6 +208,9 @@ class G1OffsetTableContigSpace: public CompactibleSpace {
|
||||
|
||||
class HeapRegion: public G1OffsetTableContigSpace {
|
||||
friend class VMStructs;
|
||||
// Allow scan_and_forward to call (private) overrides for auxiliary functions on this class
|
||||
template <typename SpaceType>
|
||||
friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp);
|
||||
private:
|
||||
|
||||
// The remembered set for this region.
|
||||
@ -219,6 +220,20 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
||||
|
||||
G1BlockOffsetArrayContigSpace* offsets() { return &_offsets; }
|
||||
|
||||
// Auxiliary functions for scan_and_forward support.
|
||||
// See comments for CompactibleSpace for more information.
|
||||
inline HeapWord* scan_limit() const {
|
||||
return top();
|
||||
}
|
||||
|
||||
inline bool scanned_block_is_obj(const HeapWord* addr) const {
|
||||
return true; // Always true, since scan_limit is top
|
||||
}
|
||||
|
||||
inline size_t scanned_block_size(const HeapWord* addr) const {
|
||||
return HeapRegion::block_size(addr); // Avoid virtual call
|
||||
}
|
||||
|
||||
protected:
|
||||
// The index of this region in the heap region sequence.
|
||||
uint _hrm_index;
|
||||
@ -340,6 +355,9 @@ class HeapRegion: public G1OffsetTableContigSpace {
|
||||
// and the amount of unallocated words if called on top()
|
||||
size_t block_size(const HeapWord* p) const;
|
||||
|
||||
// Override for scan_and_forward support.
|
||||
void prepare_for_compaction(CompactPoint* cp);
|
||||
|
||||
inline HeapWord* par_allocate_no_bot_updates(size_t word_size);
|
||||
inline HeapWord* allocate_no_bot_updates(size_t word_size);
|
||||
|
||||
|
@ -27,6 +27,7 @@
|
||||
|
||||
#include "gc_implementation/shared/markSweep.hpp"
|
||||
#include "gc_interface/collectedHeap.hpp"
|
||||
#include "oops/markOop.inline.hpp"
|
||||
#include "utilities/stack.inline.hpp"
|
||||
#include "utilities/macros.hpp"
|
||||
#if INCLUDE_ALL_GCS
|
||||
|
@ -644,10 +644,13 @@ class CollectedHeap : public CHeapObj<mtInternal> {
|
||||
// For each context in contexts, set the corresponding entries in the totals
|
||||
// and accuracy arrays to the current values held by the statistics. Each
|
||||
// array should be of length len.
|
||||
virtual void copy_allocation_context_stats(const jint* contexts,
|
||||
// Returns true if there are more stats available.
|
||||
virtual bool copy_allocation_context_stats(const jint* contexts,
|
||||
jlong* totals,
|
||||
jbyte* accuracy,
|
||||
jint len) { }
|
||||
jint len) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/////////////// Unit tests ///////////////
|
||||
|
||||
|
@ -189,11 +189,6 @@ class CollectorPolicy : public CHeapObj<mtGC> {
|
||||
return CollectorPolicy::CollectorPolicyKind;
|
||||
}
|
||||
|
||||
// Returns true if a collector has eden space with soft end.
|
||||
virtual bool has_soft_ended_eden() {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Do any updates required to global flags that are due to heap initialization
|
||||
// changes
|
||||
virtual void post_heap_initialize() = 0;
|
||||
|
@ -194,11 +194,7 @@ DefNewGeneration::DefNewGeneration(ReservedSpace rs,
|
||||
(HeapWord*)_virtual_space.high());
|
||||
Universe::heap()->barrier_set()->resize_covered_region(cmr);
|
||||
|
||||
if (GenCollectedHeap::heap()->collector_policy()->has_soft_ended_eden()) {
|
||||
_eden_space = new ConcEdenSpace(this);
|
||||
} else {
|
||||
_eden_space = new EdenSpace(this);
|
||||
}
|
||||
_eden_space = new ContiguousSpace();
|
||||
_from_space = new ContiguousSpace();
|
||||
_to_space = new ContiguousSpace();
|
||||
|
||||
@ -1038,38 +1034,12 @@ HeapWord* DefNewGeneration::allocate(size_t word_size,
|
||||
if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
|
||||
_next_gen->sample_eden_chunk();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
do {
|
||||
HeapWord* old_limit = eden()->soft_end();
|
||||
if (old_limit < eden()->end()) {
|
||||
// Tell the next generation we reached a limit.
|
||||
HeapWord* new_limit =
|
||||
next_gen()->allocation_limit_reached(eden(), eden()->top(), word_size);
|
||||
if (new_limit != NULL) {
|
||||
Atomic::cmpxchg_ptr(new_limit, eden()->soft_end_addr(), old_limit);
|
||||
} else {
|
||||
assert(eden()->soft_end() == eden()->end(),
|
||||
"invalid state after allocation_limit_reached returned null");
|
||||
}
|
||||
} else {
|
||||
// The allocation failed and the soft limit is equal to the hard limit,
|
||||
// there are no reasons to do an attempt to allocate
|
||||
assert(old_limit == eden()->end(), "sanity check");
|
||||
break;
|
||||
}
|
||||
// Try to allocate until succeeded or the soft limit can't be adjusted
|
||||
result = eden()->par_allocate(word_size);
|
||||
} while (result == NULL);
|
||||
|
||||
// If the eden is full and the last collection bailed out, we are running
|
||||
// out of heap space, and we try to allocate the from-space, too.
|
||||
// allocate_from_space can't be inlined because that would introduce a
|
||||
// circular dependency at compile time.
|
||||
if (result == NULL) {
|
||||
} else {
|
||||
// If the eden is full and the last collection bailed out, we are running
|
||||
// out of heap space, and we try to allocate the from-space, too.
|
||||
// allocate_from_space can't be inlined because that would introduce a
|
||||
// circular dependency at compile time.
|
||||
result = allocate_from_space(word_size);
|
||||
} else if (CMSEdenChunksRecordAlways && _next_gen != NULL) {
|
||||
_next_gen->sample_eden_chunk();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
@ -1083,11 +1053,6 @@ HeapWord* DefNewGeneration::par_allocate(size_t word_size,
|
||||
return res;
|
||||
}
|
||||
|
||||
void DefNewGeneration::gc_prologue(bool full) {
|
||||
// Ensure that _end and _soft_end are the same in eden space.
|
||||
eden()->set_soft_end(eden()->end());
|
||||
}
|
||||
|
||||
size_t DefNewGeneration::tlab_capacity() const {
|
||||
return eden()->capacity();
|
||||
}
|
||||
|
@ -32,7 +32,6 @@
|
||||
#include "memory/generation.inline.hpp"
|
||||
#include "utilities/stack.hpp"
|
||||
|
||||
class EdenSpace;
|
||||
class ContiguousSpace;
|
||||
class ScanClosure;
|
||||
class STWGCTimer;
|
||||
@ -132,7 +131,7 @@ protected:
|
||||
void adjust_desired_tenuring_threshold();
|
||||
|
||||
// Spaces
|
||||
EdenSpace* _eden_space;
|
||||
ContiguousSpace* _eden_space;
|
||||
ContiguousSpace* _from_space;
|
||||
ContiguousSpace* _to_space;
|
||||
|
||||
@ -214,9 +213,9 @@ protected:
|
||||
virtual Generation::Name kind() { return Generation::DefNew; }
|
||||
|
||||
// Accessing spaces
|
||||
EdenSpace* eden() const { return _eden_space; }
|
||||
ContiguousSpace* from() const { return _from_space; }
|
||||
ContiguousSpace* to() const { return _to_space; }
|
||||
ContiguousSpace* eden() const { return _eden_space; }
|
||||
ContiguousSpace* from() const { return _from_space; }
|
||||
ContiguousSpace* to() const { return _to_space; }
|
||||
|
||||
virtual CompactibleSpace* first_compaction_space() const;
|
||||
|
||||
@ -282,8 +281,6 @@ protected:
|
||||
|
||||
HeapWord* par_allocate(size_t word_size, bool is_tlab);
|
||||
|
||||
// Prologue & Epilogue
|
||||
virtual void gc_prologue(bool full);
|
||||
virtual void gc_epilogue(bool full);
|
||||
|
||||
// Save the tops for eden, from, and to
|
||||
|
@ -265,14 +265,6 @@ class Generation: public CHeapObj<mtGC> {
|
||||
// Like "allocate", but performs any necessary locking internally.
|
||||
virtual HeapWord* par_allocate(size_t word_size, bool is_tlab) = 0;
|
||||
|
||||
// A 'younger' gen has reached an allocation limit, and uses this to notify
|
||||
// the next older gen. The return value is a new limit, or NULL if none. The
|
||||
// caller must do the necessary locking.
|
||||
virtual HeapWord* allocation_limit_reached(Space* space, HeapWord* top,
|
||||
size_t word_size) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// Some generation may offer a region for shared, contiguous allocation,
|
||||
// via inlined code (by exporting the address of the top and end fields
|
||||
// defining the extent of the contiguous allocation region.)
|
||||
|
@ -438,52 +438,8 @@ bool CompactibleSpace::insert_deadspace(size_t& allowed_deadspace_words,
|
||||
}
|
||||
}
|
||||
|
||||
#define block_is_always_obj(q) true
|
||||
#define obj_size(q) oop(q)->size()
|
||||
#define adjust_obj_size(s) s
|
||||
|
||||
void CompactibleSpace::prepare_for_compaction(CompactPoint* cp) {
|
||||
SCAN_AND_FORWARD(cp, end, block_is_obj, block_size);
|
||||
}
|
||||
|
||||
// Faster object search.
|
||||
void ContiguousSpace::prepare_for_compaction(CompactPoint* cp) {
|
||||
SCAN_AND_FORWARD(cp, top, block_is_always_obj, obj_size);
|
||||
}
|
||||
|
||||
void Space::adjust_pointers() {
|
||||
// adjust all the interior pointers to point at the new locations of objects
|
||||
// Used by MarkSweep::mark_sweep_phase3()
|
||||
|
||||
// First check to see if there is any work to be done.
|
||||
if (used() == 0) {
|
||||
return; // Nothing to do.
|
||||
}
|
||||
|
||||
// Otherwise...
|
||||
HeapWord* q = bottom();
|
||||
HeapWord* t = end();
|
||||
|
||||
debug_only(HeapWord* prev_q = NULL);
|
||||
while (q < t) {
|
||||
if (oop(q)->is_gc_marked()) {
|
||||
// q is alive
|
||||
|
||||
// point all the oops to the new location
|
||||
size_t size = oop(q)->adjust_pointers();
|
||||
|
||||
debug_only(prev_q = q);
|
||||
|
||||
q += size;
|
||||
} else {
|
||||
// q is not a live object. But we're not in a compactible space,
|
||||
// So we don't have live ranges.
|
||||
debug_only(prev_q = q);
|
||||
q += block_size(q);
|
||||
assert(q > prev_q, "we should be moving forward through memory");
|
||||
}
|
||||
}
|
||||
assert(q == t, "just checking");
|
||||
scan_and_forward(this, cp);
|
||||
}
|
||||
|
||||
void CompactibleSpace::adjust_pointers() {
|
||||
@ -492,11 +448,11 @@ void CompactibleSpace::adjust_pointers() {
|
||||
return; // Nothing to do.
|
||||
}
|
||||
|
||||
SCAN_AND_ADJUST_POINTERS(adjust_obj_size);
|
||||
scan_and_adjust_pointers(this);
|
||||
}
|
||||
|
||||
void CompactibleSpace::compact() {
|
||||
SCAN_AND_COMPACT(obj_size);
|
||||
scan_and_compact(this);
|
||||
}
|
||||
|
||||
void Space::print_short() const { print_short_on(tty); }
|
||||
@ -684,13 +640,12 @@ size_t ContiguousSpace::block_size(const HeapWord* p) const {
|
||||
}
|
||||
|
||||
// This version requires locking.
|
||||
inline HeapWord* ContiguousSpace::allocate_impl(size_t size,
|
||||
HeapWord* const end_value) {
|
||||
inline HeapWord* ContiguousSpace::allocate_impl(size_t size) {
|
||||
assert(Heap_lock->owned_by_self() ||
|
||||
(SafepointSynchronize::is_at_safepoint() && Thread::current()->is_VM_thread()),
|
||||
"not locked");
|
||||
HeapWord* obj = top();
|
||||
if (pointer_delta(end_value, obj) >= size) {
|
||||
if (pointer_delta(end(), obj) >= size) {
|
||||
HeapWord* new_top = obj + size;
|
||||
set_top(new_top);
|
||||
assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
|
||||
@ -701,11 +656,10 @@ inline HeapWord* ContiguousSpace::allocate_impl(size_t size,
|
||||
}
|
||||
|
||||
// This version is lock-free.
|
||||
inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size,
|
||||
HeapWord* const end_value) {
|
||||
inline HeapWord* ContiguousSpace::par_allocate_impl(size_t size) {
|
||||
do {
|
||||
HeapWord* obj = top();
|
||||
if (pointer_delta(end_value, obj) >= size) {
|
||||
if (pointer_delta(end(), obj) >= size) {
|
||||
HeapWord* new_top = obj + size;
|
||||
HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
|
||||
// result can be one of two:
|
||||
@ -744,12 +698,12 @@ HeapWord* ContiguousSpace::allocate_aligned(size_t size) {
|
||||
|
||||
// Requires locking.
|
||||
HeapWord* ContiguousSpace::allocate(size_t size) {
|
||||
return allocate_impl(size, end());
|
||||
return allocate_impl(size);
|
||||
}
|
||||
|
||||
// Lock-free.
|
||||
HeapWord* ContiguousSpace::par_allocate(size_t size) {
|
||||
return par_allocate_impl(size, end());
|
||||
return par_allocate_impl(size);
|
||||
}
|
||||
|
||||
void ContiguousSpace::allocate_temporary_filler(int factor) {
|
||||
@ -784,49 +738,6 @@ void ContiguousSpace::allocate_temporary_filler(int factor) {
|
||||
}
|
||||
}
|
||||
|
||||
void EdenSpace::clear(bool mangle_space) {
|
||||
ContiguousSpace::clear(mangle_space);
|
||||
set_soft_end(end());
|
||||
}
|
||||
|
||||
// Requires locking.
|
||||
HeapWord* EdenSpace::allocate(size_t size) {
|
||||
return allocate_impl(size, soft_end());
|
||||
}
|
||||
|
||||
// Lock-free.
|
||||
HeapWord* EdenSpace::par_allocate(size_t size) {
|
||||
return par_allocate_impl(size, soft_end());
|
||||
}
|
||||
|
||||
HeapWord* ConcEdenSpace::par_allocate(size_t size)
|
||||
{
|
||||
do {
|
||||
// The invariant is top() should be read before end() because
|
||||
// top() can't be greater than end(), so if an update of _soft_end
|
||||
// occurs between 'end_val = end();' and 'top_val = top();' top()
|
||||
// also can grow up to the new end() and the condition
|
||||
// 'top_val > end_val' is true. To ensure the loading order
|
||||
// OrderAccess::loadload() is required after top() read.
|
||||
HeapWord* obj = top();
|
||||
OrderAccess::loadload();
|
||||
if (pointer_delta(*soft_end_addr(), obj) >= size) {
|
||||
HeapWord* new_top = obj + size;
|
||||
HeapWord* result = (HeapWord*)Atomic::cmpxchg_ptr(new_top, top_addr(), obj);
|
||||
// result can be one of two:
|
||||
// the old top value: the exchange succeeded
|
||||
// otherwise: the new value of the top is returned.
|
||||
if (result == obj) {
|
||||
assert(is_aligned(obj) && is_aligned(new_top), "checking alignment");
|
||||
return obj;
|
||||
}
|
||||
} else {
|
||||
return NULL;
|
||||
}
|
||||
} while (true);
|
||||
}
|
||||
|
||||
|
||||
HeapWord* OffsetTableContigSpace::initialize_threshold() {
|
||||
return _offsets.initialize_threshold();
|
||||
}
|
||||
|
@ -41,19 +41,6 @@
|
||||
// implementations for keeping track of free and used space,
|
||||
// for iterating over objects and free blocks, etc.
|
||||
|
||||
// Here's the Space hierarchy:
|
||||
//
|
||||
// - Space -- an abstract base class describing a heap area
|
||||
// - CompactibleSpace -- a space supporting compaction
|
||||
// - CompactibleFreeListSpace -- (used for CMS generation)
|
||||
// - ContiguousSpace -- a compactible space in which all free space
|
||||
// is contiguous
|
||||
// - EdenSpace -- contiguous space used as nursery
|
||||
// - ConcEdenSpace -- contiguous space with a 'soft end safe' allocation
|
||||
// - OffsetTableContigSpace -- contiguous space with a block offset array
|
||||
// that allows "fast" block_start calls
|
||||
// - TenuredSpace -- (used for TenuredGeneration)
|
||||
|
||||
// Forward decls.
|
||||
class Space;
|
||||
class BlockOffsetArray;
|
||||
@ -238,7 +225,7 @@ class Space: public CHeapObj<mtGC> {
|
||||
|
||||
// Mark-sweep-compact support: all spaces can update pointers to objects
|
||||
// moving as a part of compaction.
|
||||
virtual void adjust_pointers();
|
||||
virtual void adjust_pointers() = 0;
|
||||
|
||||
// PrintHeapAtGC support
|
||||
virtual void print() const;
|
||||
@ -339,7 +326,36 @@ public:
|
||||
// necessarily, a space that is normally contiguous. But, for example, a
|
||||
// free-list-based space whose normal collection is a mark-sweep without
|
||||
// compaction could still support compaction in full GC's.
|
||||
|
||||
//
|
||||
// The compaction operations are implemented by the
|
||||
// scan_and_{adjust_pointers,compact,forward} function templates.
|
||||
// The following are, non-virtual, auxiliary functions used by these function templates:
|
||||
// - scan_limit()
|
||||
// - scanned_block_is_obj()
|
||||
// - scanned_block_size()
|
||||
// - adjust_obj_size()
|
||||
// - obj_size()
|
||||
// These functions are to be used exclusively by the scan_and_* function templates,
|
||||
// and must be defined for all (non-abstract) subclasses of CompactibleSpace.
|
||||
//
|
||||
// NOTE: Any subclasses to CompactibleSpace wanting to change/define the behavior
|
||||
// in any of the auxiliary functions must also override the corresponding
|
||||
// prepare_for_compaction/adjust_pointers/compact functions using them.
|
||||
// If not, such changes will not be used or have no effect on the compaction operations.
|
||||
//
|
||||
// This translates to the following dependencies:
|
||||
// Overrides/definitions of
|
||||
// - scan_limit
|
||||
// - scanned_block_is_obj
|
||||
// - scanned_block_size
|
||||
// require override/definition of prepare_for_compaction().
|
||||
// Similar dependencies exist between
|
||||
// - adjust_obj_size and adjust_pointers()
|
||||
// - obj_size and compact().
|
||||
//
|
||||
// Additionally, this also means that changes to block_size() or block_is_obj() that
|
||||
// should be effective during the compaction operations must provide a corresponding
|
||||
// definition of scanned_block_size/scanned_block_is_obj respectively.
|
||||
class CompactibleSpace: public Space {
|
||||
friend class VMStructs;
|
||||
friend class CompactibleFreeListSpace;
|
||||
@ -347,6 +363,15 @@ private:
|
||||
HeapWord* _compaction_top;
|
||||
CompactibleSpace* _next_compaction_space;
|
||||
|
||||
// Auxiliary functions for scan_and_{forward,adjust_pointers,compact} support.
|
||||
inline size_t adjust_obj_size(size_t size) const {
|
||||
return size;
|
||||
}
|
||||
|
||||
inline size_t obj_size(const HeapWord* addr) const {
|
||||
return oop(addr)->size();
|
||||
}
|
||||
|
||||
public:
|
||||
CompactibleSpace() :
|
||||
_compaction_top(NULL), _next_compaction_space(NULL) {}
|
||||
@ -390,7 +415,7 @@ public:
|
||||
// "cp->compaction_space" up-to-date. Offset tables may be updated in
|
||||
// this phase as if the final copy had occurred; if so, "cp->threshold"
|
||||
// indicates when the next such action should be taken.
|
||||
virtual void prepare_for_compaction(CompactPoint* cp);
|
||||
virtual void prepare_for_compaction(CompactPoint* cp) = 0;
|
||||
// MarkSweep support phase3
|
||||
virtual void adjust_pointers();
|
||||
// MarkSweep support phase4
|
||||
@ -449,6 +474,25 @@ protected:
|
||||
// words remaining after this operation.
|
||||
bool insert_deadspace(size_t& allowed_deadspace_words, HeapWord* q,
|
||||
size_t word_len);
|
||||
|
||||
// Below are template functions for scan_and_* algorithms (avoiding virtual calls).
|
||||
// The space argument should be a subclass of CompactibleSpace, implementing
|
||||
// scan_limit(), scanned_block_is_obj(), and scanned_block_size(),
|
||||
// and possibly also overriding obj_size(), and adjust_obj_size().
|
||||
// These functions should avoid virtual calls whenever possible.
|
||||
|
||||
// Frequently calls adjust_obj_size().
|
||||
template <class SpaceType>
|
||||
static inline void scan_and_adjust_pointers(SpaceType* space);
|
||||
|
||||
// Frequently calls obj_size().
|
||||
template <class SpaceType>
|
||||
static inline void scan_and_compact(SpaceType* space);
|
||||
|
||||
// Frequently calls scanned_block_is_obj() and scanned_block_size().
|
||||
// Requires the scan_limit() function.
|
||||
template <class SpaceType>
|
||||
static inline void scan_and_forward(SpaceType* space, CompactPoint* cp);
|
||||
};
|
||||
|
||||
class GenSpaceMangler;
|
||||
@ -458,6 +502,25 @@ class GenSpaceMangler;
|
||||
class ContiguousSpace: public CompactibleSpace {
|
||||
friend class OneContigSpaceCardGeneration;
|
||||
friend class VMStructs;
|
||||
// Allow scan_and_forward function to call (private) overrides for auxiliary functions on this class
|
||||
template <typename SpaceType>
|
||||
friend void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp);
|
||||
|
||||
private:
|
||||
// Auxiliary functions for scan_and_forward support.
|
||||
// See comments for CompactibleSpace for more information.
|
||||
inline HeapWord* scan_limit() const {
|
||||
return top();
|
||||
}
|
||||
|
||||
inline bool scanned_block_is_obj(const HeapWord* addr) const {
|
||||
return true; // Always true, since scan_limit is top
|
||||
}
|
||||
|
||||
inline size_t scanned_block_size(const HeapWord* addr) const {
|
||||
return oop(addr)->size();
|
||||
}
|
||||
|
||||
protected:
|
||||
HeapWord* _top;
|
||||
HeapWord* _concurrent_iteration_safe_limit;
|
||||
@ -467,8 +530,8 @@ class ContiguousSpace: public CompactibleSpace {
|
||||
GenSpaceMangler* mangler() { return _mangler; }
|
||||
|
||||
// Allocation helpers (return NULL if full).
|
||||
inline HeapWord* allocate_impl(size_t word_size, HeapWord* end_value);
|
||||
inline HeapWord* par_allocate_impl(size_t word_size, HeapWord* end_value);
|
||||
inline HeapWord* allocate_impl(size_t word_size);
|
||||
inline HeapWord* par_allocate_impl(size_t word_size);
|
||||
|
||||
public:
|
||||
ContiguousSpace();
|
||||
@ -622,7 +685,6 @@ class ContiguousSpace: public CompactibleSpace {
|
||||
// Used to increase collection frequency. "factor" of 0 means entire
|
||||
// space.
|
||||
void allocate_temporary_filler(int factor);
|
||||
|
||||
};
|
||||
|
||||
|
||||
@ -685,56 +747,6 @@ public:
|
||||
{}
|
||||
};
|
||||
|
||||
|
||||
// Class EdenSpace describes eden-space in new generation.
|
||||
|
||||
class DefNewGeneration;
|
||||
|
||||
class EdenSpace : public ContiguousSpace {
|
||||
friend class VMStructs;
|
||||
private:
|
||||
DefNewGeneration* _gen;
|
||||
|
||||
// _soft_end is used as a soft limit on allocation. As soft limits are
|
||||
// reached, the slow-path allocation code can invoke other actions and then
|
||||
// adjust _soft_end up to a new soft limit or to end().
|
||||
HeapWord* _soft_end;
|
||||
|
||||
public:
|
||||
EdenSpace(DefNewGeneration* gen) :
|
||||
_gen(gen), _soft_end(NULL) {}
|
||||
|
||||
// Get/set just the 'soft' limit.
|
||||
HeapWord* soft_end() { return _soft_end; }
|
||||
HeapWord** soft_end_addr() { return &_soft_end; }
|
||||
void set_soft_end(HeapWord* value) { _soft_end = value; }
|
||||
|
||||
// Override.
|
||||
void clear(bool mangle_space);
|
||||
|
||||
// Set both the 'hard' and 'soft' limits (_end and _soft_end).
|
||||
void set_end(HeapWord* value) {
|
||||
set_soft_end(value);
|
||||
ContiguousSpace::set_end(value);
|
||||
}
|
||||
|
||||
// Allocation (return NULL if full)
|
||||
HeapWord* allocate(size_t word_size);
|
||||
HeapWord* par_allocate(size_t word_size);
|
||||
};
|
||||
|
||||
// Class ConcEdenSpace extends EdenSpace for the sake of safe
|
||||
// allocation while soft-end is being modified concurrently
|
||||
|
||||
class ConcEdenSpace : public EdenSpace {
|
||||
public:
|
||||
ConcEdenSpace(DefNewGeneration* gen) : EdenSpace(gen) { }
|
||||
|
||||
// Allocation (return NULL if full)
|
||||
HeapWord* par_allocate(size_t word_size);
|
||||
};
|
||||
|
||||
|
||||
// A ContigSpace that Supports an efficient "block_start" operation via
|
||||
// a BlockOffsetArray (whose BlockOffsetSharedArray may be shared with
|
||||
// other spaces.) This is the abstract base class for old generation
|
||||
|
@ -25,6 +25,9 @@
|
||||
#ifndef SHARE_VM_MEMORY_SPACE_INLINE_HPP
|
||||
#define SHARE_VM_MEMORY_SPACE_INLINE_HPP
|
||||
|
||||
#include "gc_implementation/shared/liveRange.hpp"
|
||||
#include "gc_implementation/shared/markSweep.inline.hpp"
|
||||
#include "gc_implementation/shared/spaceDecorator.hpp"
|
||||
#include "gc_interface/collectedHeap.hpp"
|
||||
#include "memory/space.hpp"
|
||||
#include "memory/universe.hpp"
|
||||
@ -35,272 +38,6 @@ inline HeapWord* Space::block_start(const void* p) {
|
||||
return block_start_const(p);
|
||||
}
|
||||
|
||||
#define SCAN_AND_FORWARD(cp,scan_limit,block_is_obj,block_size) { \
|
||||
/* Compute the new addresses for the live objects and store it in the mark \
|
||||
* Used by universe::mark_sweep_phase2() \
|
||||
*/ \
|
||||
HeapWord* compact_top; /* This is where we are currently compacting to. */ \
|
||||
\
|
||||
/* We're sure to be here before any objects are compacted into this \
|
||||
* space, so this is a good time to initialize this: \
|
||||
*/ \
|
||||
set_compaction_top(bottom()); \
|
||||
\
|
||||
if (cp->space == NULL) { \
|
||||
assert(cp->gen != NULL, "need a generation"); \
|
||||
assert(cp->threshold == NULL, "just checking"); \
|
||||
assert(cp->gen->first_compaction_space() == this, "just checking"); \
|
||||
cp->space = cp->gen->first_compaction_space(); \
|
||||
compact_top = cp->space->bottom(); \
|
||||
cp->space->set_compaction_top(compact_top); \
|
||||
cp->threshold = cp->space->initialize_threshold(); \
|
||||
} else { \
|
||||
compact_top = cp->space->compaction_top(); \
|
||||
} \
|
||||
\
|
||||
/* We allow some amount of garbage towards the bottom of the space, so \
|
||||
* we don't start compacting before there is a significant gain to be made.\
|
||||
* Occasionally, we want to ensure a full compaction, which is determined \
|
||||
* by the MarkSweepAlwaysCompactCount parameter. \
|
||||
*/ \
|
||||
uint invocations = MarkSweep::total_invocations(); \
|
||||
bool skip_dead = ((invocations % MarkSweepAlwaysCompactCount) != 0); \
|
||||
\
|
||||
size_t allowed_deadspace = 0; \
|
||||
if (skip_dead) { \
|
||||
const size_t ratio = allowed_dead_ratio(); \
|
||||
allowed_deadspace = (capacity() * ratio / 100) / HeapWordSize; \
|
||||
} \
|
||||
\
|
||||
HeapWord* q = bottom(); \
|
||||
HeapWord* t = scan_limit(); \
|
||||
\
|
||||
HeapWord* end_of_live= q; /* One byte beyond the last byte of the last \
|
||||
live object. */ \
|
||||
HeapWord* first_dead = end();/* The first dead object. */ \
|
||||
LiveRange* liveRange = NULL; /* The current live range, recorded in the \
|
||||
first header of preceding free area. */ \
|
||||
_first_dead = first_dead; \
|
||||
\
|
||||
const intx interval = PrefetchScanIntervalInBytes; \
|
||||
\
|
||||
while (q < t) { \
|
||||
assert(!block_is_obj(q) || \
|
||||
oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() || \
|
||||
oop(q)->mark()->has_bias_pattern(), \
|
||||
"these are the only valid states during a mark sweep"); \
|
||||
if (block_is_obj(q) && oop(q)->is_gc_marked()) { \
|
||||
/* prefetch beyond q */ \
|
||||
Prefetch::write(q, interval); \
|
||||
size_t size = block_size(q); \
|
||||
compact_top = cp->space->forward(oop(q), size, cp, compact_top); \
|
||||
q += size; \
|
||||
end_of_live = q; \
|
||||
} else { \
|
||||
/* run over all the contiguous dead objects */ \
|
||||
HeapWord* end = q; \
|
||||
do { \
|
||||
/* prefetch beyond end */ \
|
||||
Prefetch::write(end, interval); \
|
||||
end += block_size(end); \
|
||||
} while (end < t && (!block_is_obj(end) || !oop(end)->is_gc_marked()));\
|
||||
\
|
||||
/* see if we might want to pretend this object is alive so that \
|
||||
* we don't have to compact quite as often. \
|
||||
*/ \
|
||||
if (allowed_deadspace > 0 && q == compact_top) { \
|
||||
size_t sz = pointer_delta(end, q); \
|
||||
if (insert_deadspace(allowed_deadspace, q, sz)) { \
|
||||
compact_top = cp->space->forward(oop(q), sz, cp, compact_top); \
|
||||
q = end; \
|
||||
end_of_live = end; \
|
||||
continue; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* otherwise, it really is a free region. */ \
|
||||
\
|
||||
/* for the previous LiveRange, record the end of the live objects. */ \
|
||||
if (liveRange) { \
|
||||
liveRange->set_end(q); \
|
||||
} \
|
||||
\
|
||||
/* record the current LiveRange object. \
|
||||
* liveRange->start() is overlaid on the mark word. \
|
||||
*/ \
|
||||
liveRange = (LiveRange*)q; \
|
||||
liveRange->set_start(end); \
|
||||
liveRange->set_end(end); \
|
||||
\
|
||||
/* see if this is the first dead region. */ \
|
||||
if (q < first_dead) { \
|
||||
first_dead = q; \
|
||||
} \
|
||||
\
|
||||
/* move on to the next object */ \
|
||||
q = end; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
assert(q == t, "just checking"); \
|
||||
if (liveRange != NULL) { \
|
||||
liveRange->set_end(q); \
|
||||
} \
|
||||
_end_of_live = end_of_live; \
|
||||
if (end_of_live < first_dead) { \
|
||||
first_dead = end_of_live; \
|
||||
} \
|
||||
_first_dead = first_dead; \
|
||||
\
|
||||
/* save the compaction_top of the compaction space. */ \
|
||||
cp->space->set_compaction_top(compact_top); \
|
||||
}
|
||||
|
||||
#define SCAN_AND_ADJUST_POINTERS(adjust_obj_size) { \
|
||||
/* adjust all the interior pointers to point at the new locations of objects \
|
||||
* Used by MarkSweep::mark_sweep_phase3() */ \
|
||||
\
|
||||
HeapWord* q = bottom(); \
|
||||
HeapWord* t = _end_of_live; /* Established by "prepare_for_compaction". */ \
|
||||
\
|
||||
assert(_first_dead <= _end_of_live, "Stands to reason, no?"); \
|
||||
\
|
||||
if (q < t && _first_dead > q && \
|
||||
!oop(q)->is_gc_marked()) { \
|
||||
/* we have a chunk of the space which hasn't moved and we've \
|
||||
* reinitialized the mark word during the previous pass, so we can't \
|
||||
* use is_gc_marked for the traversal. */ \
|
||||
HeapWord* end = _first_dead; \
|
||||
\
|
||||
while (q < end) { \
|
||||
/* I originally tried to conjoin "block_start(q) == q" to the \
|
||||
* assertion below, but that doesn't work, because you can't \
|
||||
* accurately traverse previous objects to get to the current one \
|
||||
* after their pointers have been \
|
||||
* updated, until the actual compaction is done. dld, 4/00 */ \
|
||||
assert(block_is_obj(q), \
|
||||
"should be at block boundaries, and should be looking at objs"); \
|
||||
\
|
||||
/* point all the oops to the new location */ \
|
||||
size_t size = oop(q)->adjust_pointers(); \
|
||||
size = adjust_obj_size(size); \
|
||||
\
|
||||
q += size; \
|
||||
} \
|
||||
\
|
||||
if (_first_dead == t) { \
|
||||
q = t; \
|
||||
} else { \
|
||||
/* $$$ This is funky. Using this to read the previously written \
|
||||
* LiveRange. See also use below. */ \
|
||||
q = (HeapWord*)oop(_first_dead)->mark()->decode_pointer(); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
const intx interval = PrefetchScanIntervalInBytes; \
|
||||
\
|
||||
debug_only(HeapWord* prev_q = NULL); \
|
||||
while (q < t) { \
|
||||
/* prefetch beyond q */ \
|
||||
Prefetch::write(q, interval); \
|
||||
if (oop(q)->is_gc_marked()) { \
|
||||
/* q is alive */ \
|
||||
/* point all the oops to the new location */ \
|
||||
size_t size = oop(q)->adjust_pointers(); \
|
||||
size = adjust_obj_size(size); \
|
||||
debug_only(prev_q = q); \
|
||||
q += size; \
|
||||
} else { \
|
||||
/* q is not a live object, so its mark should point at the next \
|
||||
* live object */ \
|
||||
debug_only(prev_q = q); \
|
||||
q = (HeapWord*) oop(q)->mark()->decode_pointer(); \
|
||||
assert(q > prev_q, "we should be moving forward through memory"); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
assert(q == t, "just checking"); \
|
||||
}
|
||||
|
||||
#define SCAN_AND_COMPACT(obj_size) { \
|
||||
/* Copy all live objects to their new location \
|
||||
* Used by MarkSweep::mark_sweep_phase4() */ \
|
||||
\
|
||||
HeapWord* q = bottom(); \
|
||||
HeapWord* const t = _end_of_live; \
|
||||
debug_only(HeapWord* prev_q = NULL); \
|
||||
\
|
||||
if (q < t && _first_dead > q && \
|
||||
!oop(q)->is_gc_marked()) { \
|
||||
debug_only( \
|
||||
/* we have a chunk of the space which hasn't moved and we've reinitialized \
|
||||
* the mark word during the previous pass, so we can't use is_gc_marked for \
|
||||
* the traversal. */ \
|
||||
HeapWord* const end = _first_dead; \
|
||||
\
|
||||
while (q < end) { \
|
||||
size_t size = obj_size(q); \
|
||||
assert(!oop(q)->is_gc_marked(), \
|
||||
"should be unmarked (special dense prefix handling)"); \
|
||||
debug_only(prev_q = q); \
|
||||
q += size; \
|
||||
} \
|
||||
) /* debug_only */ \
|
||||
\
|
||||
if (_first_dead == t) { \
|
||||
q = t; \
|
||||
} else { \
|
||||
/* $$$ Funky */ \
|
||||
q = (HeapWord*) oop(_first_dead)->mark()->decode_pointer(); \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
const intx scan_interval = PrefetchScanIntervalInBytes; \
|
||||
const intx copy_interval = PrefetchCopyIntervalInBytes; \
|
||||
while (q < t) { \
|
||||
if (!oop(q)->is_gc_marked()) { \
|
||||
/* mark is pointer to next marked oop */ \
|
||||
debug_only(prev_q = q); \
|
||||
q = (HeapWord*) oop(q)->mark()->decode_pointer(); \
|
||||
assert(q > prev_q, "we should be moving forward through memory"); \
|
||||
} else { \
|
||||
/* prefetch beyond q */ \
|
||||
Prefetch::read(q, scan_interval); \
|
||||
\
|
||||
/* size and destination */ \
|
||||
size_t size = obj_size(q); \
|
||||
HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee(); \
|
||||
\
|
||||
/* prefetch beyond compaction_top */ \
|
||||
Prefetch::write(compaction_top, copy_interval); \
|
||||
\
|
||||
/* copy object and reinit its mark */ \
|
||||
assert(q != compaction_top, "everything in this pass should be moving"); \
|
||||
Copy::aligned_conjoint_words(q, compaction_top, size); \
|
||||
oop(compaction_top)->init_mark(); \
|
||||
assert(oop(compaction_top)->klass() != NULL, "should have a class"); \
|
||||
\
|
||||
debug_only(prev_q = q); \
|
||||
q += size; \
|
||||
} \
|
||||
} \
|
||||
\
|
||||
/* Let's remember if we were empty before we did the compaction. */ \
|
||||
bool was_empty = used_region().is_empty(); \
|
||||
/* Reset space after compaction is complete */ \
|
||||
reset_after_compaction(); \
|
||||
/* We do this clear, below, since it has overloaded meanings for some */ \
|
||||
/* space subtypes. For example, OffsetTableContigSpace's that were */ \
|
||||
/* compacted into will have had their offset table thresholds updated */ \
|
||||
/* continuously, but those that weren't need to have their thresholds */ \
|
||||
/* re-initialized. Also mangles unused area for debugging. */ \
|
||||
if (used_region().is_empty()) { \
|
||||
if (!was_empty) clear(SpaceDecorator::Mangle); \
|
||||
} else { \
|
||||
if (ZapUnusedHeapArea) mangle_unused_area(); \
|
||||
} \
|
||||
}
|
||||
|
||||
inline HeapWord* OffsetTableContigSpace::allocate(size_t size) {
|
||||
HeapWord* res = ContiguousSpace::allocate(size);
|
||||
if (res != NULL) {
|
||||
@ -334,4 +71,263 @@ OffsetTableContigSpace::block_start_const(const void* p) const {
|
||||
return _offsets.block_start(p);
|
||||
}
|
||||
|
||||
template <class SpaceType>
|
||||
inline void CompactibleSpace::scan_and_forward(SpaceType* space, CompactPoint* cp) {
|
||||
// Compute the new addresses for the live objects and store it in the mark
|
||||
// Used by universe::mark_sweep_phase2()
|
||||
HeapWord* compact_top; // This is where we are currently compacting to.
|
||||
|
||||
// We're sure to be here before any objects are compacted into this
|
||||
// space, so this is a good time to initialize this:
|
||||
space->set_compaction_top(space->bottom());
|
||||
|
||||
if (cp->space == NULL) {
|
||||
assert(cp->gen != NULL, "need a generation");
|
||||
assert(cp->threshold == NULL, "just checking");
|
||||
assert(cp->gen->first_compaction_space() == space, "just checking");
|
||||
cp->space = cp->gen->first_compaction_space();
|
||||
compact_top = cp->space->bottom();
|
||||
cp->space->set_compaction_top(compact_top);
|
||||
cp->threshold = cp->space->initialize_threshold();
|
||||
} else {
|
||||
compact_top = cp->space->compaction_top();
|
||||
}
|
||||
|
||||
// We allow some amount of garbage towards the bottom of the space, so
|
||||
// we don't start compacting before there is a significant gain to be made.
|
||||
// Occasionally, we want to ensure a full compaction, which is determined
|
||||
// by the MarkSweepAlwaysCompactCount parameter.
|
||||
uint invocations = MarkSweep::total_invocations();
|
||||
bool skip_dead = ((invocations % MarkSweepAlwaysCompactCount) != 0);
|
||||
|
||||
size_t allowed_deadspace = 0;
|
||||
if (skip_dead) {
|
||||
const size_t ratio = space->allowed_dead_ratio();
|
||||
allowed_deadspace = (space->capacity() * ratio / 100) / HeapWordSize;
|
||||
}
|
||||
|
||||
HeapWord* q = space->bottom();
|
||||
HeapWord* t = space->scan_limit();
|
||||
|
||||
HeapWord* end_of_live= q; // One byte beyond the last byte of the last
|
||||
// live object.
|
||||
HeapWord* first_dead = space->end(); // The first dead object.
|
||||
LiveRange* liveRange = NULL; // The current live range, recorded in the
|
||||
// first header of preceding free area.
|
||||
space->_first_dead = first_dead;
|
||||
|
||||
const intx interval = PrefetchScanIntervalInBytes;
|
||||
|
||||
while (q < t) {
|
||||
assert(!space->scanned_block_is_obj(q) ||
|
||||
oop(q)->mark()->is_marked() || oop(q)->mark()->is_unlocked() ||
|
||||
oop(q)->mark()->has_bias_pattern(),
|
||||
"these are the only valid states during a mark sweep");
|
||||
if (space->scanned_block_is_obj(q) && oop(q)->is_gc_marked()) {
|
||||
// prefetch beyond q
|
||||
Prefetch::write(q, interval);
|
||||
size_t size = space->scanned_block_size(q);
|
||||
compact_top = cp->space->forward(oop(q), size, cp, compact_top);
|
||||
q += size;
|
||||
end_of_live = q;
|
||||
} else {
|
||||
// run over all the contiguous dead objects
|
||||
HeapWord* end = q;
|
||||
do {
|
||||
// prefetch beyond end
|
||||
Prefetch::write(end, interval);
|
||||
end += space->scanned_block_size(end);
|
||||
} while (end < t && (!space->scanned_block_is_obj(end) || !oop(end)->is_gc_marked()));
|
||||
|
||||
// see if we might want to pretend this object is alive so that
|
||||
// we don't have to compact quite as often.
|
||||
if (allowed_deadspace > 0 && q == compact_top) {
|
||||
size_t sz = pointer_delta(end, q);
|
||||
if (space->insert_deadspace(allowed_deadspace, q, sz)) {
|
||||
compact_top = cp->space->forward(oop(q), sz, cp, compact_top);
|
||||
q = end;
|
||||
end_of_live = end;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// otherwise, it really is a free region.
|
||||
|
||||
// for the previous LiveRange, record the end of the live objects.
|
||||
if (liveRange) {
|
||||
liveRange->set_end(q);
|
||||
}
|
||||
|
||||
// record the current LiveRange object.
|
||||
// liveRange->start() is overlaid on the mark word.
|
||||
liveRange = (LiveRange*)q;
|
||||
liveRange->set_start(end);
|
||||
liveRange->set_end(end);
|
||||
|
||||
// see if this is the first dead region.
|
||||
if (q < first_dead) {
|
||||
first_dead = q;
|
||||
}
|
||||
|
||||
// move on to the next object
|
||||
q = end;
|
||||
}
|
||||
}
|
||||
|
||||
assert(q == t, "just checking");
|
||||
if (liveRange != NULL) {
|
||||
liveRange->set_end(q);
|
||||
}
|
||||
space->_end_of_live = end_of_live;
|
||||
if (end_of_live < first_dead) {
|
||||
first_dead = end_of_live;
|
||||
}
|
||||
space->_first_dead = first_dead;
|
||||
|
||||
// save the compaction_top of the compaction space.
|
||||
cp->space->set_compaction_top(compact_top);
|
||||
}
|
||||
|
||||
template <class SpaceType>
|
||||
inline void CompactibleSpace::scan_and_adjust_pointers(SpaceType* space) {
|
||||
// adjust all the interior pointers to point at the new locations of objects
|
||||
// Used by MarkSweep::mark_sweep_phase3()
|
||||
|
||||
HeapWord* q = space->bottom();
|
||||
HeapWord* t = space->_end_of_live; // Established by "prepare_for_compaction".
|
||||
|
||||
assert(space->_first_dead <= space->_end_of_live, "Stands to reason, no?");
|
||||
|
||||
if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) {
|
||||
// we have a chunk of the space which hasn't moved and we've
|
||||
// reinitialized the mark word during the previous pass, so we can't
|
||||
// use is_gc_marked for the traversal.
|
||||
HeapWord* end = space->_first_dead;
|
||||
|
||||
while (q < end) {
|
||||
// I originally tried to conjoin "block_start(q) == q" to the
|
||||
// assertion below, but that doesn't work, because you can't
|
||||
// accurately traverse previous objects to get to the current one
|
||||
// after their pointers have been
|
||||
// updated, until the actual compaction is done. dld, 4/00
|
||||
assert(space->block_is_obj(q), "should be at block boundaries, and should be looking at objs");
|
||||
|
||||
// point all the oops to the new location
|
||||
size_t size = oop(q)->adjust_pointers();
|
||||
size = space->adjust_obj_size(size);
|
||||
|
||||
q += size;
|
||||
}
|
||||
|
||||
if (space->_first_dead == t) {
|
||||
q = t;
|
||||
} else {
|
||||
// $$$ This is funky. Using this to read the previously written
|
||||
// LiveRange. See also use below.
|
||||
q = (HeapWord*)oop(space->_first_dead)->mark()->decode_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
const intx interval = PrefetchScanIntervalInBytes;
|
||||
|
||||
debug_only(HeapWord* prev_q = NULL);
|
||||
while (q < t) {
|
||||
// prefetch beyond q
|
||||
Prefetch::write(q, interval);
|
||||
if (oop(q)->is_gc_marked()) {
|
||||
// q is alive
|
||||
// point all the oops to the new location
|
||||
size_t size = oop(q)->adjust_pointers();
|
||||
size = space->adjust_obj_size(size);
|
||||
debug_only(prev_q = q);
|
||||
q += size;
|
||||
} else {
|
||||
// q is not a live object, so its mark should point at the next
|
||||
// live object
|
||||
debug_only(prev_q = q);
|
||||
q = (HeapWord*) oop(q)->mark()->decode_pointer();
|
||||
assert(q > prev_q, "we should be moving forward through memory");
|
||||
}
|
||||
}
|
||||
|
||||
assert(q == t, "just checking");
|
||||
}
|
||||
|
||||
template <class SpaceType>
|
||||
inline void CompactibleSpace::scan_and_compact(SpaceType* space) {
|
||||
// Copy all live objects to their new location
|
||||
// Used by MarkSweep::mark_sweep_phase4()
|
||||
|
||||
HeapWord* q = space->bottom();
|
||||
HeapWord* const t = space->_end_of_live;
|
||||
debug_only(HeapWord* prev_q = NULL);
|
||||
|
||||
if (q < t && space->_first_dead > q && !oop(q)->is_gc_marked()) {
|
||||
#ifdef ASSERT // Debug only
|
||||
// we have a chunk of the space which hasn't moved and we've reinitialized
|
||||
// the mark word during the previous pass, so we can't use is_gc_marked for
|
||||
// the traversal.
|
||||
HeapWord* const end = space->_first_dead;
|
||||
|
||||
while (q < end) {
|
||||
size_t size = space->obj_size(q);
|
||||
assert(!oop(q)->is_gc_marked(), "should be unmarked (special dense prefix handling)");
|
||||
prev_q = q;
|
||||
q += size;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (space->_first_dead == t) {
|
||||
q = t;
|
||||
} else {
|
||||
// $$$ Funky
|
||||
q = (HeapWord*) oop(space->_first_dead)->mark()->decode_pointer();
|
||||
}
|
||||
}
|
||||
|
||||
const intx scan_interval = PrefetchScanIntervalInBytes;
|
||||
const intx copy_interval = PrefetchCopyIntervalInBytes;
|
||||
while (q < t) {
|
||||
if (!oop(q)->is_gc_marked()) {
|
||||
// mark is pointer to next marked oop
|
||||
debug_only(prev_q = q);
|
||||
q = (HeapWord*) oop(q)->mark()->decode_pointer();
|
||||
assert(q > prev_q, "we should be moving forward through memory");
|
||||
} else {
|
||||
// prefetch beyond q
|
||||
Prefetch::read(q, scan_interval);
|
||||
|
||||
// size and destination
|
||||
size_t size = space->obj_size(q);
|
||||
HeapWord* compaction_top = (HeapWord*)oop(q)->forwardee();
|
||||
|
||||
// prefetch beyond compaction_top
|
||||
Prefetch::write(compaction_top, copy_interval);
|
||||
|
||||
// copy object and reinit its mark
|
||||
assert(q != compaction_top, "everything in this pass should be moving");
|
||||
Copy::aligned_conjoint_words(q, compaction_top, size);
|
||||
oop(compaction_top)->init_mark();
|
||||
assert(oop(compaction_top)->klass() != NULL, "should have a class");
|
||||
|
||||
debug_only(prev_q = q);
|
||||
q += size;
|
||||
}
|
||||
}
|
||||
|
||||
// Let's remember if we were empty before we did the compaction.
|
||||
bool was_empty = space->used_region().is_empty();
|
||||
// Reset space after compaction is complete
|
||||
space->reset_after_compaction();
|
||||
// We do this clear, below, since it has overloaded meanings for some
|
||||
// space subtypes. For example, OffsetTableContigSpace's that were
|
||||
// compacted into will have had their offset table thresholds updated
|
||||
// continuously, but those that weren't need to have their thresholds
|
||||
// re-initialized. Also mangles unused area for debugging.
|
||||
if (space->used_region().is_empty()) {
|
||||
if (!was_empty) space->clear(SpaceDecorator::Mangle);
|
||||
} else {
|
||||
if (ZapUnusedHeapArea) space->mangle_unused_area();
|
||||
}
|
||||
}
|
||||
#endif // SHARE_VM_MEMORY_SPACE_INLINE_HPP
|
||||
|
@ -1197,8 +1197,7 @@ void PhaseMacroExpand::expand_allocate_common(
|
||||
}
|
||||
|
||||
if (C->env()->dtrace_alloc_probes() ||
|
||||
!UseTLAB && (!Universe::heap()->supports_inline_contig_alloc() ||
|
||||
(UseConcMarkSweepGC && CMSIncrementalMode))) {
|
||||
!UseTLAB && (!Universe::heap()->supports_inline_contig_alloc())) {
|
||||
// Force slow-path allocation
|
||||
always_slow = true;
|
||||
initial_slow_test = NULL;
|
||||
|
@ -1777,7 +1777,7 @@ void Arguments::set_g1_gc_flags() {
|
||||
#ifdef ASSERT
|
||||
static bool verify_serial_gc_flags() {
|
||||
return (UseSerialGC &&
|
||||
!(UseParNewGC || (UseConcMarkSweepGC || CMSIncrementalMode) || UseG1GC ||
|
||||
!(UseParNewGC || (UseConcMarkSweepGC) || UseG1GC ||
|
||||
UseParallelGC || UseParallelOldGC));
|
||||
}
|
||||
#endif // ASSERT
|
||||
@ -2191,10 +2191,6 @@ void Arguments::check_deprecated_gcs() {
|
||||
warning("Using the ParNew young collector with the Serial old collector is deprecated "
|
||||
"and will likely be removed in a future release");
|
||||
}
|
||||
|
||||
if (CMSIncrementalMode) {
|
||||
warning("Using incremental CMS is deprecated and will likely be removed in a future release");
|
||||
}
|
||||
}
|
||||
|
||||
void Arguments::check_deprecated_gc_flags() {
|
||||
@ -2316,31 +2312,8 @@ bool Arguments::check_vm_args_consistency() {
|
||||
status = status && ArgumentsExt::check_gc_consistency_user();
|
||||
status = status && check_stack_pages();
|
||||
|
||||
if (CMSIncrementalMode) {
|
||||
if (!UseConcMarkSweepGC) {
|
||||
jio_fprintf(defaultStream::error_stream(),
|
||||
"error: invalid argument combination.\n"
|
||||
"The CMS collector (-XX:+UseConcMarkSweepGC) must be "
|
||||
"selected in order\nto use CMSIncrementalMode.\n");
|
||||
status = false;
|
||||
} else {
|
||||
status = status && verify_percentage(CMSIncrementalDutyCycle,
|
||||
"CMSIncrementalDutyCycle");
|
||||
status = status && verify_percentage(CMSIncrementalDutyCycleMin,
|
||||
"CMSIncrementalDutyCycleMin");
|
||||
status = status && verify_percentage(CMSIncrementalSafetyFactor,
|
||||
"CMSIncrementalSafetyFactor");
|
||||
status = status && verify_percentage(CMSIncrementalOffset,
|
||||
"CMSIncrementalOffset");
|
||||
status = status && verify_percentage(CMSExpAvgFactor,
|
||||
"CMSExpAvgFactor");
|
||||
// If it was not set on the command line, set
|
||||
// CMSInitiatingOccupancyFraction to 1 so icms can initiate cycles early.
|
||||
if (CMSInitiatingOccupancyFraction < 0) {
|
||||
FLAG_SET_DEFAULT(CMSInitiatingOccupancyFraction, 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
status = status && verify_percentage(CMSIncrementalSafetyFactor,
|
||||
"CMSIncrementalSafetyFactor");
|
||||
|
||||
// CMS space iteration, which FLSVerifyAllHeapreferences entails,
|
||||
// insists that we hold the requisite locks so that the iteration is
|
||||
@ -2874,14 +2847,6 @@ jint Arguments::parse_each_vm_init_arg(const JavaVMInitArgs* args,
|
||||
// -Xnoclassgc
|
||||
} else if (match_option(option, "-Xnoclassgc", &tail)) {
|
||||
FLAG_SET_CMDLINE(bool, ClassUnloading, false);
|
||||
// -Xincgc: i-CMS
|
||||
} else if (match_option(option, "-Xincgc", &tail)) {
|
||||
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
|
||||
FLAG_SET_CMDLINE(bool, CMSIncrementalMode, true);
|
||||
// -Xnoincgc: no i-CMS
|
||||
} else if (match_option(option, "-Xnoincgc", &tail)) {
|
||||
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, false);
|
||||
FLAG_SET_CMDLINE(bool, CMSIncrementalMode, false);
|
||||
// -Xconcgc
|
||||
} else if (match_option(option, "-Xconcgc", &tail)) {
|
||||
FLAG_SET_CMDLINE(bool, UseConcMarkSweepGC, true);
|
||||
@ -3711,7 +3676,6 @@ void Arguments::set_shared_spaces_flags() {
|
||||
#if !INCLUDE_ALL_GCS
|
||||
static void force_serial_gc() {
|
||||
FLAG_SET_DEFAULT(UseSerialGC, true);
|
||||
FLAG_SET_DEFAULT(CMSIncrementalMode, false); // special CMS suboption
|
||||
UNSUPPORTED_GC_OPTION(UseG1GC);
|
||||
UNSUPPORTED_GC_OPTION(UseParallelGC);
|
||||
UNSUPPORTED_GC_OPTION(UseParallelOldGC);
|
||||
|
@ -1638,30 +1638,10 @@ class CommandLineFlags {
|
||||
"The maximum size of young gen chosen by default per GC worker " \
|
||||
"thread available") \
|
||||
\
|
||||
product(bool, CMSIncrementalMode, false, \
|
||||
"Whether CMS GC should operate in \"incremental\" mode") \
|
||||
\
|
||||
product(uintx, CMSIncrementalDutyCycle, 10, \
|
||||
"Percentage (0-100) of CMS incremental mode duty cycle. If " \
|
||||
"CMSIncrementalPacing is enabled, then this is just the initial " \
|
||||
"value.") \
|
||||
\
|
||||
product(bool, CMSIncrementalPacing, true, \
|
||||
"Whether the CMS incremental mode duty cycle should be " \
|
||||
"automatically adjusted") \
|
||||
\
|
||||
product(uintx, CMSIncrementalDutyCycleMin, 0, \
|
||||
"Minimum percentage (0-100) of the CMS incremental duty cycle " \
|
||||
"used when CMSIncrementalPacing is enabled") \
|
||||
\
|
||||
product(uintx, CMSIncrementalSafetyFactor, 10, \
|
||||
"Percentage (0-100) used to add conservatism when computing the " \
|
||||
"duty cycle") \
|
||||
\
|
||||
product(uintx, CMSIncrementalOffset, 0, \
|
||||
"Percentage (0-100) by which the CMS incremental mode duty cycle "\
|
||||
"is shifted to the right within the period between young GCs") \
|
||||
\
|
||||
product(uintx, CMSExpAvgFactor, 50, \
|
||||
"Percentage (0-100) used to weight the current sample when " \
|
||||
"computing exponential averages for CMS statistics") \
|
||||
@ -1720,15 +1700,6 @@ class CommandLineFlags {
|
||||
"Skip block flux-rate sampling for an epoch unless inter-sweep " \
|
||||
"duration exceeds this threshold in milliseconds") \
|
||||
\
|
||||
develop(bool, CMSTraceIncrementalMode, false, \
|
||||
"Trace CMS incremental mode") \
|
||||
\
|
||||
develop(bool, CMSTraceIncrementalPacing, false, \
|
||||
"Trace CMS incremental mode pacing computation") \
|
||||
\
|
||||
develop(bool, CMSTraceThreadState, false, \
|
||||
"Trace the CMS thread state (enable the trace_state() method)") \
|
||||
\
|
||||
product(bool, CMSClassUnloadingEnabled, true, \
|
||||
"Whether class unloading enabled when using CMS GC") \
|
||||
\
|
||||
|
@ -72,7 +72,6 @@ Monitor* Threads_lock = NULL;
|
||||
Monitor* CGC_lock = NULL;
|
||||
Monitor* STS_lock = NULL;
|
||||
Monitor* SLT_lock = NULL;
|
||||
Monitor* iCMS_lock = NULL;
|
||||
Monitor* FullGCCount_lock = NULL;
|
||||
Monitor* CMark_lock = NULL;
|
||||
Mutex* CMRegionStack_lock = NULL;
|
||||
@ -175,9 +174,6 @@ void mutex_init() {
|
||||
|
||||
def(CGC_lock , Monitor, special, true ); // coordinate between fore- and background GC
|
||||
def(STS_lock , Monitor, leaf, true );
|
||||
if (UseConcMarkSweepGC) {
|
||||
def(iCMS_lock , Monitor, special, true ); // CMS incremental mode start/stop notification
|
||||
}
|
||||
if (UseConcMarkSweepGC || UseG1GC) {
|
||||
def(FullGCCount_lock , Monitor, leaf, true ); // in support of ExplicitGCInvokesConcurrent
|
||||
}
|
||||
|
@ -66,7 +66,6 @@ extern Monitor* CGC_lock; // used for coordination betwee
|
||||
// fore- & background GC threads.
|
||||
extern Monitor* STS_lock; // used for joining/leaving SuspendibleThreadSet.
|
||||
extern Monitor* SLT_lock; // used in CMS GC for acquiring PLL
|
||||
extern Monitor* iCMS_lock; // CMS incremental mode start/stop notification
|
||||
extern Monitor* FullGCCount_lock; // in support of "concurrent" full gc
|
||||
extern Monitor* CMark_lock; // used for concurrent mark thread coordination
|
||||
extern Mutex* CMRegionStack_lock; // used for protecting accesses to the CM region stack
|
||||
|
@ -527,12 +527,10 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||
nonstatic_field(DefNewGeneration, _next_gen, Generation*) \
|
||||
nonstatic_field(DefNewGeneration, _tenuring_threshold, uint) \
|
||||
nonstatic_field(DefNewGeneration, _age_table, ageTable) \
|
||||
nonstatic_field(DefNewGeneration, _eden_space, EdenSpace*) \
|
||||
nonstatic_field(DefNewGeneration, _eden_space, ContiguousSpace*) \
|
||||
nonstatic_field(DefNewGeneration, _from_space, ContiguousSpace*) \
|
||||
nonstatic_field(DefNewGeneration, _to_space, ContiguousSpace*) \
|
||||
\
|
||||
nonstatic_field(EdenSpace, _gen, DefNewGeneration*) \
|
||||
\
|
||||
nonstatic_field(Generation, _reserved, MemRegion) \
|
||||
nonstatic_field(Generation, _virtual_space, VirtualSpace) \
|
||||
nonstatic_field(Generation, _level, int) \
|
||||
@ -1490,7 +1488,6 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||
declare_toplevel_type(BitMap) \
|
||||
declare_type(CompactibleSpace, Space) \
|
||||
declare_type(ContiguousSpace, CompactibleSpace) \
|
||||
declare_type(EdenSpace, ContiguousSpace) \
|
||||
declare_type(OffsetTableContigSpace, ContiguousSpace) \
|
||||
declare_type(TenuredSpace, OffsetTableContigSpace) \
|
||||
declare_toplevel_type(BarrierSet) \
|
||||
@ -1532,7 +1529,6 @@ typedef TwoOopHashtable<Symbol*, mtClass> SymbolTwoOopHashtable;
|
||||
declare_toplevel_type(CollectedHeap*) \
|
||||
declare_toplevel_type(ContiguousSpace*) \
|
||||
declare_toplevel_type(DefNewGeneration*) \
|
||||
declare_toplevel_type(EdenSpace*) \
|
||||
declare_toplevel_type(GenCollectedHeap*) \
|
||||
declare_toplevel_type(Generation*) \
|
||||
declare_toplevel_type(GenerationSpec**) \
|
||||
|
@ -175,11 +175,8 @@ needs_full_vm_compact1 = \
|
||||
gc/g1/TestShrinkToOneRegion.java \
|
||||
gc/metaspace/G1AddMetaspaceDependency.java \
|
||||
gc/startup_warnings/TestCMS.java \
|
||||
gc/startup_warnings/TestCMSIncrementalMode.java \
|
||||
gc/startup_warnings/TestCMSNoIncrementalMode.java \
|
||||
gc/startup_warnings/TestDefaultMaxRAMFraction.java \
|
||||
gc/startup_warnings/TestDefNewCMS.java \
|
||||
gc/startup_warnings/TestIncGC.java \
|
||||
gc/startup_warnings/TestParallelGC.java \
|
||||
gc/startup_warnings/TestParallelScavengeSerialOld.java \
|
||||
gc/startup_warnings/TestParNewCMS.java \
|
||||
@ -274,8 +271,6 @@ needs_cmsgc = \
|
||||
gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java \
|
||||
gc/concurrentMarkSweep/ \
|
||||
gc/startup_warnings/TestCMS.java \
|
||||
gc/startup_warnings/TestCMSIncrementalMode.java \
|
||||
gc/startup_warnings/TestCMSNoIncrementalMode.java \
|
||||
gc/startup_warnings/TestDefNewCMS.java \
|
||||
gc/startup_warnings/TestParNewCMS.java
|
||||
|
||||
|
@ -279,8 +279,7 @@ public class TestShrinkAuxiliaryData {
|
||||
"-XX:\\+UseConcMarkSweepGC",
|
||||
"-XX:\\+UseParallelOldGC",
|
||||
"-XX:\\+UseParNewGC",
|
||||
"-Xconcgc",
|
||||
"-Xincgc"
|
||||
"-Xconcgc"
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -1,46 +0,0 @@
|
||||
|
||||
/*
|
||||
* Copyright (c) 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestCMSIncrementalMode
|
||||
* @key gc
|
||||
* @bug 8006398
|
||||
* @summary Test that the deprecated CMSIncrementalMode print a warning message
|
||||
* @library /testlibrary
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
public class TestCMSIncrementalMode {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:+CMSIncrementalMode", "-version");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release");
|
||||
output.shouldNotContain("error");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
}
|
@ -1,45 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestCMSNoIncrementalMode
|
||||
* @key gc
|
||||
* @bug 8006398
|
||||
* @summary Test that CMS with incremental mode turned off does not print a warning message
|
||||
* @library /testlibrary
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
public class TestCMSNoIncrementalMode {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseConcMarkSweepGC", "-XX:-CMSIncrementalMode", "-version");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldNotContain("deprecated");
|
||||
output.shouldNotContain("error");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test TestIncGC
|
||||
* @key gc
|
||||
* @bug 8006398
|
||||
* @summary Test that the deprecated -Xincgc print a warning message
|
||||
* @library /testlibrary
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
|
||||
public class TestIncGC {
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-Xincgc", "-version");
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
output.shouldContain("warning: Using incremental CMS is deprecated and will likely be removed in a future release");
|
||||
output.shouldNotContain("error");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
}
|
Loading…
Reference in New Issue
Block a user