src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File
hotspot Cdiff src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
Print this page
rev 5732 : [mq]: comments2
*** 115,128 ****
//
// Unfortunately, i couldn't come up with a good abstraction to factor and
// hide the naked CGC_lock manipulation in the baton-passing code
// further below. That's something we should try to do. Also, the proof
// of correctness of this 2-level locking scheme is far from obvious,
! // and potentially quite slippery. We have an uneasy supsicion, for instance,
// that there may be a theoretical possibility of delay/starvation in the
// low-level lock/wait/notify scheme used for the baton-passing because of
! // potential intereference with the priority scheme embodied in the
// CMS-token-passing protocol. See related comments at a CGC_lock->wait()
// invocation further below and marked with "XXX 20011219YSR".
// Indeed, as we note elsewhere, this may become yet more slippery
// in the presence of multiple CMS and/or multiple VM threads. XXX
--- 115,128 ----
//
// Unfortunately, i couldn't come up with a good abstraction to factor and
// hide the naked CGC_lock manipulation in the baton-passing code
// further below. That's something we should try to do. Also, the proof
// of correctness of this 2-level locking scheme is far from obvious,
! // and potentially quite slippery. We have an uneasy suspicion, for instance,
// that there may be a theoretical possibility of delay/starvation in the
// low-level lock/wait/notify scheme used for the baton-passing because of
! // potential interference with the priority scheme embodied in the
// CMS-token-passing protocol. See related comments at a CGC_lock->wait()
// invocation further below and marked with "XXX 20011219YSR".
// Indeed, as we note elsewhere, this may become yet more slippery
// in the presence of multiple CMS and/or multiple VM threads. XXX
*** 257,267 ****
// generation may be larger than that in, say, a contiguous young
// generation.
// Ideally, in the calculation below, we'd compute the dilatation
// factor as: MinChunkSize/(promoting_gen's min object size)
// Since we do not have such a general query interface for the
! // promoting generation, we'll instead just use the mimimum
// object size (which today is a header's worth of space);
// note that all arithmetic is in units of HeapWords.
assert(MinChunkSize >= CollectedHeap::min_fill_size(), "just checking");
assert(_dilatation_factor >= 1.0, "from previous assert");
}
--- 257,267 ----
// generation may be larger than that in, say, a contiguous young
// generation.
// Ideally, in the calculation below, we'd compute the dilatation
// factor as: MinChunkSize/(promoting_gen's min object size)
// Since we do not have such a general query interface for the
! // promoting generation, we'll instead just use the minimum
// object size (which today is a header's worth of space);
// note that all arithmetic is in units of HeapWords.
assert(MinChunkSize >= CollectedHeap::min_fill_size(), "just checking");
assert(_dilatation_factor >= 1.0, "from previous assert");
}
*** 272,282 ****
// via CMSInitiatingOccupancyFraction (argument "io" below), it
// is calculated by:
//
// Let "f" be MinHeapFreeRatio in
//
! // _intiating_occupancy = 100-f +
// f * (CMSTriggerRatio/100)
// where CMSTriggerRatio is the argument "tr" below.
//
// That is, if we assume the heap is at its desired maximum occupancy at the
// end of a collection, we let CMSTriggerRatio of the (purported) free
--- 272,282 ----
// via CMSInitiatingOccupancyFraction (argument "io" below), it
// is calculated by:
//
// Let "f" be MinHeapFreeRatio in
//
! // _initiating_occupancy = 100-f +
// f * (CMSTriggerRatio/100)
// where CMSTriggerRatio is the argument "tr" below.
//
// That is, if we assume the heap is at its desired maximum occupancy at the
// end of a collection, we let CMSTriggerRatio of the (purported) free
*** 2669,2679 ****
// prologue delegate to the collector, which delegates back
// some "local" work to a worker method in the individual generations
// that it's responsible for collecting, while itself doing any
// work common to all generations it's responsible for. A similar
// comment applies to the gc_epilogue()'s.
! // The role of the varaible _between_prologue_and_epilogue is to
// enforce the invocation protocol.
void CMSCollector::gc_prologue(bool full) {
// Call gc_prologue_work() for the CMSGen
// we are responsible for.
--- 2669,2679 ----
// prologue delegate to the collector, which delegates back
// some "local" work to a worker method in the individual generations
// that it's responsible for collecting, while itself doing any
// work common to all generations it's responsible for. A similar
// comment applies to the gc_epilogue()'s.
! // The role of the variable _between_prologue_and_epilogue is to
// enforce the invocation protocol.
void CMSCollector::gc_prologue(bool full) {
// Call gc_prologue_work() for the CMSGen
// we are responsible for.
*** 2876,2889 ****
#endif
// Check reachability of the given heap address in CMS generation,
// treating all other generations as roots.
bool CMSCollector::is_cms_reachable(HeapWord* addr) {
! // We could "guarantee" below, rather than assert, but i'll
// leave these as "asserts" so that an adventurous debugger
// could try this in the product build provided some subset of
! // the conditions were met, provided they were intersted in the
// results and knew that the computation below wouldn't interfere
// with other concurrent computations mutating the structures
// being read or written.
assert(SafepointSynchronize::is_at_safepoint(),
"Else mutations in object graph will make answer suspect");
--- 2876,2889 ----
#endif
// Check reachability of the given heap address in CMS generation,
// treating all other generations as roots.
bool CMSCollector::is_cms_reachable(HeapWord* addr) {
! // We could "guarantee" below, rather than assert, but I'll
// leave these as "asserts" so that an adventurous debugger
// could try this in the product build provided some subset of
! // the conditions were met, provided they were interested in the
// results and knew that the computation below wouldn't interfere
// with other concurrent computations mutating the structures
// being read or written.
assert(SafepointSynchronize::is_at_safepoint(),
"Else mutations in object graph will make answer suspect");
*** 2980,2990 ****
// Turn off refs discovery -- so we will be tracing through refs.
// This is as intended, because by this time
// GC must already have cleared any refs that need to be cleared,
// and traced those that need to be marked; moreover,
! // the marking done here is not going to intefere in any
// way with the marking information used by GC.
NoRefDiscovery no_discovery(ref_processor());
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
--- 2980,2990 ----
// Turn off refs discovery -- so we will be tracing through refs.
// This is as intended, because by this time
// GC must already have cleared any refs that need to be cleared,
// and traced those that need to be marked; moreover,
! // the marking done here is not going to interfere in any
// way with the marking information used by GC.
NoRefDiscovery no_discovery(ref_processor());
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
*** 2998,3008 ****
// Update the saved marks which may affect the root scans.
gch->save_marks();
if (CMSRemarkVerifyVariant == 1) {
// In this first variant of verification, we complete
! // all marking, then check if the new marks-verctor is
// a subset of the CMS marks-vector.
verify_after_remark_work_1();
} else if (CMSRemarkVerifyVariant == 2) {
// In this second variant of verification, we flag an error
// (i.e. an object reachable in the new marks-vector not reachable
--- 2998,3008 ----
// Update the saved marks which may affect the root scans.
gch->save_marks();
if (CMSRemarkVerifyVariant == 1) {
// In this first variant of verification, we complete
! // all marking, then check if the new marks-vector is
// a subset of the CMS marks-vector.
verify_after_remark_work_1();
} else if (CMSRemarkVerifyVariant == 2) {
// In this second variant of verification, we flag an error
// (i.e. an object reachable in the new marks-vector not reachable
*** 3399,3409 ****
// Otherwise, we try expansion.
expand(word_sz*HeapWordSize, MinHeapDeltaBytes,
CMSExpansionCause::_allocate_par_lab);
// Now go around the loop and try alloc again;
// A competing par_promote might beat us to the expansion space,
! // so we may go around the loop again if promotion fails agaion.
if (GCExpandToAllocateDelayMillis > 0) {
os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
}
}
}
--- 3399,3409 ----
// Otherwise, we try expansion.
expand(word_sz*HeapWordSize, MinHeapDeltaBytes,
CMSExpansionCause::_allocate_par_lab);
// Now go around the loop and try alloc again;
// A competing par_promote might beat us to the expansion space,
! // so we may go around the loop again if promotion fails again.
if (GCExpandToAllocateDelayMillis > 0) {
os::sleep(Thread::current(), GCExpandToAllocateDelayMillis, false);
}
}
}
*** 4371,4381 ****
// We really need to reconsider the synchronization between the GC
// thread and the yield-requesting threads in the future and we
// should really use wait/notify, which is the recommended
// way of doing this type of interaction. Additionally, we should
// consolidate the eight methods that do the yield operation and they
! // are almost identical into one for better maintenability and
// readability. See 6445193.
//
// Tony 2006.06.29
for (unsigned i = 0; i < CMSCoordinatorYieldSleepCount &&
ConcurrentMarkSweepThread::should_yield() &&
--- 4371,4381 ----
// We really need to reconsider the synchronization between the GC
// thread and the yield-requesting threads in the future and we
// should really use wait/notify, which is the recommended
// way of doing this type of interaction. Additionally, we should
// consolidate the eight methods that do the yield operation and they
! // are almost identical into one for better maintainability and
// readability. See 6445193.
//
// Tony 2006.06.29
for (unsigned i = 0; i < CMSCoordinatorYieldSleepCount &&
ConcurrentMarkSweepThread::should_yield() &&
*** 4539,4549 ****
assert(_collectorState == AbortablePreclean, "Inconsistent control state");
// If Eden's current occupancy is below this threshold,
// immediately schedule the remark; else preclean
// past the next scavenge in an effort to
! // schedule the pause as described avove. By choosing
// CMSScheduleRemarkEdenSizeThreshold >= max eden size
// we will never do an actual abortable preclean cycle.
if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) {
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "abortable-preclean", !PrintGCDetails);
--- 4539,4549 ----
assert(_collectorState == AbortablePreclean, "Inconsistent control state");
// If Eden's current occupancy is below this threshold,
// immediately schedule the remark; else preclean
// past the next scavenge in an effort to
! // schedule the pause as described above. By choosing
// CMSScheduleRemarkEdenSizeThreshold >= max eden size
// we will never do an actual abortable preclean cycle.
if (get_eden_used() > CMSScheduleRemarkEdenSizeThreshold) {
TraceCPUTime tcpu(PrintGCDetails, true, gclog_or_tty);
CMSPhaseAccounting pa(this, "abortable-preclean", !PrintGCDetails);
*** 5535,5546 ****
OopTaskQueue* work_q = work_queue(i);
ModUnionClosure modUnionClosure(&(_collector->_modUnionTable));
// CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! CAUTION!
// CAUTION: This closure has state that persists across calls to
// the work method dirty_range_iterate_clear() in that it has
! // imbedded in it a (subtype of) UpwardsObjectClosure. The
! // use of that state in the imbedded UpwardsObjectClosure instance
// assumes that the cards are always iterated (even if in parallel
// by several threads) in monotonically increasing order per each
// thread. This is true of the implementation below which picks
// card ranges (chunks) in monotonically increasing order globally
// and, a-fortiori, in monotonically increasing order per thread
--- 5535,5546 ----
OopTaskQueue* work_q = work_queue(i);
ModUnionClosure modUnionClosure(&(_collector->_modUnionTable));
// CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! CAUTION! CAUTION!
// CAUTION: This closure has state that persists across calls to
// the work method dirty_range_iterate_clear() in that it has
! // embedded in it a (subtype of) UpwardsObjectClosure. The
! // use of that state in the embedded UpwardsObjectClosure instance
// assumes that the cards are always iterated (even if in parallel
// by several threads) in monotonically increasing order per each
// thread. This is true of the implementation below which picks
// card ranges (chunks) in monotonically increasing order globally
// and, a-fortiori, in monotonically increasing order per thread
*** 5551,5561 ****
// revisited and modified appropriately. See also related
// bug 4756801 work on which should examine this code to make
// sure that the changes there do not run counter to the
// assumptions made here and necessary for correctness and
// efficiency. Note also that this code might yield inefficient
! // behaviour in the case of very large objects that span one or
// more work chunks. Such objects would potentially be scanned
// several times redundantly. Work on 4756801 should try and
// address that performance anomaly if at all possible. XXX
MemRegion full_span = _collector->_span;
CMSBitMap* bm = &(_collector->_markBitMap); // shared
--- 5551,5561 ----
// revisited and modified appropriately. See also related
// bug 4756801 work on which should examine this code to make
// sure that the changes there do not run counter to the
// assumptions made here and necessary for correctness and
// efficiency. Note also that this code might yield inefficient
! // behavior in the case of very large objects that span one or
// more work chunks. Such objects would potentially be scanned
// several times redundantly. Work on 4756801 should try and
// address that performance anomaly if at all possible. XXX
MemRegion full_span = _collector->_span;
CMSBitMap* bm = &(_collector->_markBitMap); // shared
*** 5577,5587 ****
assert((size_t)round_to((intptr_t)chunk_size, alignment) ==
chunk_size, "Check alignment");
while (!pst->is_task_claimed(/* reference */ nth_task)) {
// Having claimed the nth_task, compute corresponding mem-region,
! // which is a-fortiori aligned correctly (i.e. at a MUT bopundary).
// The alignment restriction ensures that we do not need any
// synchronization with other gang-workers while setting or
// clearing bits in thus chunk of the MUT.
MemRegion this_span = MemRegion(start_addr + nth_task*chunk_size,
start_addr + (nth_task+1)*chunk_size);
--- 5577,5587 ----
assert((size_t)round_to((intptr_t)chunk_size, alignment) ==
chunk_size, "Check alignment");
while (!pst->is_task_claimed(/* reference */ nth_task)) {
// Having claimed the nth_task, compute corresponding mem-region,
! // which is a-fortiori aligned correctly (i.e. at a MUT boundary).
// The alignment restriction ensures that we do not need any
// synchronization with other gang-workers while setting or
// clearing bits in thus chunk of the MUT.
MemRegion this_span = MemRegion(start_addr + nth_task*chunk_size,
start_addr + (nth_task+1)*chunk_size);
*** 6369,6379 ****
_intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
! // We need to use a monotonically non-deccreasing time in ms
// or we will see time-warp warnings and os::javaTimeMillis()
// does not guarantee monotonicity.
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
--- 6369,6379 ----
_intra_sweep_estimate.sample(_intra_sweep_timer.seconds());
_inter_sweep_timer.reset();
_inter_sweep_timer.start();
! // We need to use a monotonically non-decreasing time in ms
// or we will see time-warp warnings and os::javaTimeMillis()
// does not guarantee monotonicity.
jlong now = os::javaTimeNanos() / NANOSECS_PER_MILLISEC;
update_time_of_last_gc(now);
*** 6730,6740 ****
(_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
if (!brs.is_reserved()) {
warning("CMS bit map allocation failure");
return false;
}
! // For now we'll just commit all of the bit map up fromt.
// Later on we'll try to be more parsimonious with swap.
if (!_virtual_space.initialize(brs, brs.size())) {
warning("CMS bit map backing store failure");
return false;
}
--- 6730,6740 ----
(_bmWordSize >> (_shifter + LogBitsPerByte)) + 1));
if (!brs.is_reserved()) {
warning("CMS bit map allocation failure");
return false;
}
! // For now we'll just commit all of the bit map up front.
// Later on we'll try to be more parsimonious with swap.
if (!_virtual_space.initialize(brs, brs.size())) {
warning("CMS bit map backing store failure");
return false;
}
*** 6837,6848 ****
return true;
}
// XXX FIX ME !!! In the MT case we come in here holding a
// leaf lock. For printing we need to take a further lock
! // which has lower rank. We need to recallibrate the two
! // lock-ranks involved in order to be able to rpint the
// messages below. (Or defer the printing to the caller.
// For now we take the expedient path of just disabling the
// messages for the problematic case.)
void CMSMarkStack::expand() {
assert(_capacity <= MarkStackSizeMax, "stack bigger than permitted");
--- 6837,6848 ----
return true;
}
// XXX FIX ME !!! In the MT case we come in here holding a
// leaf lock. For printing we need to take a further lock
! // which has lower rank. We need to recalibrate the two
! // lock-ranks involved in order to be able to print the
// messages below. (Or defer the printing to the caller.
// For now we take the expedient path of just disabling the
// messages for the problematic case.)
void CMSMarkStack::expand() {
assert(_capacity <= MarkStackSizeMax, "stack bigger than permitted");
*** 7178,7196 ****
assert(_bitMap->isMarked(addr+size-1),
"inconsistent Printezis mark");
}
#endif // ASSERT
} else {
! // an unitialized object
assert(_bitMap->isMarked(addr+1), "missing Printezis mark?");
HeapWord* nextOneAddr = _bitMap->getNextMarkedWordAddress(addr + 2);
size = pointer_delta(nextOneAddr + 1, addr);
assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
"alignment problem");
// Note that pre-cleaning needn't redirty the card. OopDesc::set_klass()
// will dirty the card when the klass pointer is installed in the
! // object (signalling the completion of initialization).
}
} else {
// Either a not yet marked object or an uninitialized object
if (p->klass_or_null() == NULL) {
// An uninitialized object, skip to the next card, since
--- 7178,7196 ----
assert(_bitMap->isMarked(addr+size-1),
"inconsistent Printezis mark");
}
#endif // ASSERT
} else {
! // An uninitialized object.
assert(_bitMap->isMarked(addr+1), "missing Printezis mark?");
HeapWord* nextOneAddr = _bitMap->getNextMarkedWordAddress(addr + 2);
size = pointer_delta(nextOneAddr + 1, addr);
assert(size == CompactibleFreeListSpace::adjustObjectSize(size),
"alignment problem");
// Note that pre-cleaning needn't redirty the card. OopDesc::set_klass()
// will dirty the card when the klass pointer is installed in the
! // object (signaling the completion of initialization).
}
} else {
// Either a not yet marked object or an uninitialized object
if (p->klass_or_null() == NULL) {
// An uninitialized object, skip to the next card, since
*** 7997,8007 ****
// in the mod union table, thus ensuring that the object remains
// in the grey set and continue. In the case of object arrays
// we need to dirty all of the cards that the object spans,
// since the rescan of object arrays will be limited to the
// dirty cards.
! // Note that no one can be intefering with us in this action
// of dirtying the mod union table, so no locking or atomics
// are required.
if (obj->is_objArray()) {
size_t sz = obj->size();
HeapWord* end_card_addr = (HeapWord*)round_to(
--- 7997,8007 ----
// in the mod union table, thus ensuring that the object remains
// in the grey set and continue. In the case of object arrays
// we need to dirty all of the cards that the object spans,
// since the rescan of object arrays will be limited to the
// dirty cards.
! // Note that no one can be interfering with us in this action
// of dirtying the mod union table, so no locking or atomics
// are required.
if (obj->is_objArray()) {
size_t sz = obj->size();
HeapWord* end_card_addr = (HeapWord*)round_to(
*** 9023,9033 ****
#ifndef PRODUCT
// Debugging support for CMSStackOverflowALot
// It's OK to call this multi-threaded; the worst thing
// that can happen is that we'll get a bunch of closely
! // spaced simulated oveflows, but that's OK, in fact
// probably good as it would exercise the overflow code
// under contention.
bool CMSCollector::simulate_overflow() {
if (_overflow_counter-- <= 0) { // just being defensive
_overflow_counter = CMSMarkStackOverflowInterval;
--- 9023,9033 ----
#ifndef PRODUCT
// Debugging support for CMSStackOverflowALot
// It's OK to call this multi-threaded; the worst thing
// that can happen is that we'll get a bunch of closely
! // spaced simulated overflows, but that's OK, in fact
// probably good as it would exercise the overflow code
// under contention.
bool CMSCollector::simulate_overflow() {
if (_overflow_counter-- <= 0) { // just being defensive
_overflow_counter = CMSMarkStackOverflowInterval;
*** 9143,9153 ****
// above, if it is still the same value.
if (_overflow_list == BUSY) {
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
}
} else {
! // Chop off the suffix and rerturn it to the global list.
assert(cur->mark() != BUSY, "Error");
oop suffix_head = cur->mark(); // suffix will be put back on global list
cur->set_mark(NULL); // break off suffix
// It's possible that the list is still in the empty(busy) state
// we left it in a short while ago; in that case we may be
--- 9143,9153 ----
// above, if it is still the same value.
if (_overflow_list == BUSY) {
(void) Atomic::cmpxchg_ptr(NULL, &_overflow_list, BUSY);
}
} else {
! // Chop off the suffix and return it to the global list.
assert(cur->mark() != BUSY, "Error");
oop suffix_head = cur->mark(); // suffix will be put back on global list
cur->set_mark(NULL); // break off suffix
// It's possible that the list is still in the empty(busy) state
// we left it in a short while ago; in that case we may be
src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
Index
Unified diffs
Context diffs
Sdiffs
Patch
New
Old
Previous File
Next File