src/share/vm/gc_implementation/concurrentMarkSweep/concurrentMarkSweepGeneration.cpp
Print this page
@@ -565,10 +565,11 @@
_overflow_list(NULL),
_stats(cmsGen),
_eden_chunk_array(NULL), // may be set in ctor body
_eden_chunk_capacity(0), // -- ditto --
_eden_chunk_index(0), // -- ditto --
+ _eden_chunk_sampling_active(0),
_survivor_plab_array(NULL), // -- ditto --
_survivor_chunk_array(NULL), // -- ditto --
_survivor_chunk_capacity(0), // -- ditto --
_survivor_chunk_index(0), // -- ditto --
_ser_pmc_preclean_ovflw(0),
@@ -2098,10 +2099,43 @@
// For a mark-sweep, compute_new_size() will be called
// in the heap's do_collection() method.
}
+void CMSCollector::print_eden_and_survivor_chunk_arrays() {
+ DefNewGeneration* dng = _young_gen->as_DefNewGeneration();
+ EdenSpace* eden_space = dng->eden();
+ ContiguousSpace* from_space = dng->from();
+ ContiguousSpace* to_space = dng->to();
+ // Eden
+ if (_eden_chunk_array) {
+ gclog_or_tty->print_cr("eden " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")",
+ eden_space->bottom(), eden_space->top(),
+ eden_space->end(), eden_space->capacity());
+ gclog_or_tty->print_cr("_eden_chunk_index=" SIZE_FORMAT ", "
+ "_eden_chunk_capacity=" SIZE_FORMAT,
+ _eden_chunk_index, _eden_chunk_capacity);
+ for (size_t i = 0; i < _eden_chunk_index; i++) {
+ gclog_or_tty->print_cr("_eden_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT,
+ i, _eden_chunk_array[i]);
+ }
+ }
+ // Survivor
+ if (_survivor_chunk_array) {
+ gclog_or_tty->print_cr("survivor " PTR_FORMAT "-" PTR_FORMAT "-" PTR_FORMAT "(" SIZE_FORMAT ")",
+ from_space->bottom(), from_space->top(),
+ from_space->end(), from_space->capacity());
+ gclog_or_tty->print_cr("_survivor_chunk_index=" SIZE_FORMAT ", "
+ "_survivor_chunk_capacity=" SIZE_FORMAT,
+ _survivor_chunk_index, _survivor_chunk_capacity);
+ for (size_t i = 0; i < _survivor_chunk_index; i++) {
+ gclog_or_tty->print_cr("_survivor_chunk_array[" SIZE_FORMAT "]=" PTR_FORMAT,
+ i, _survivor_chunk_array[i]);
+ }
+ }
+}
+
void CMSCollector::getFreelistLocks() const {
// Get locks for all free lists in all generations that this
// collector is responsible for
_cmsGen->freelistLock()->lock_without_safepoint_check();
}
@@ -3589,10 +3623,14 @@
// Whenever a CLD is found, it will be claimed before proceeding to mark
// the klasses. The claimed marks need to be cleared before marking starts.
ClassLoaderDataGraph::clear_claimed_marks();
+ if (CMSPrintEdenSurvivorChunks) {
+ print_eden_and_survivor_chunk_arrays();
+ }
+
CMKlassClosure klass_closure(¬Older);
{
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
gch->rem_set()->prepare_for_younger_refs_iterate(false); // Not parallel.
gch->gen_process_strong_roots(_cmsGen->level(),
@@ -4360,11 +4398,13 @@
assert(Thread::current()->is_ConcurrentGC_thread(), "Wrong thread");
verify_work_stacks_empty();
verify_overflow_empty();
_abort_preclean = false;
if (CMSPrecleaningEnabled) {
+ if (!CMSEdenChunksRecordAlways) {
_eden_chunk_index = 0;
+ }
size_t used = get_eden_used();
size_t capacity = get_eden_capacity();
// Don't start sampling unless we will get sufficiently
// many samples.
if (used < (capacity/(CMSScheduleRemarkSamplingRatio * 100)
@@ -4469,11 +4509,13 @@
assert(ConcurrentMarkSweepThread::cms_thread_has_cms_token(),
"Should collect samples while holding CMS token");
if (!_start_sampling) {
return;
}
- if (_eden_chunk_array) {
+ // When CMSEdenChunksRecordAlways is true, the eden chunk array
+ // is populated by the young generation.
+ if (_eden_chunk_array && !CMSEdenChunksRecordAlways) {
if (_eden_chunk_index < _eden_chunk_capacity) {
_eden_chunk_array[_eden_chunk_index] = *_top_addr; // take sample
assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
"Unexpected state of Eden");
// We'd like to check that what we just sampled is an oop-start address;
@@ -4951,10 +4993,14 @@
// so here just in case a scavenge did not happen.
gch->ensure_parsability(false); // fill TLAB's, but no need to retire them
// Update the saved marks which may affect the root scans.
gch->save_marks();
+ if (CMSPrintEdenSurvivorChunks) {
+ print_eden_and_survivor_chunk_arrays();
+ }
+
{
COMPILER2_PRESENT(DerivedPointerTableDeactivate dpt_deact;)
// Note on the role of the mod union table:
// Since the marker in "markFromRoots" marks concurrently with
@@ -5469,10 +5515,62 @@
)
assert(work_q->size() == 0 && _collector->overflow_list_is_empty(),
"Else our work is not yet done");
}
+// Record object boundaries in _eden_chunk_array by sampling the eden
+// top in the slow-path eden object allocation code path and record
+// the boundaries, if CMSEdenChunksRecordAlways is true. If
+// CMSEdenChunksRecordAlways is false, we use the other asynchronous
+// sampling in sample_eden() that activates during the part of the
+// preclean phase.
+void CMSCollector::sample_eden_chunk() {
+ // A CAS-based (lock-free) sampling mechanism. Since this is called
+ // from the young gen allocation code path (albeit the slow path),
+ // it's important that this code is quick.
+ if (CMSEdenChunksRecordAlways && _eden_chunk_array) {
+ bool do_sampling = false;
+ do {
+ jbyte sampling_active = _eden_chunk_sampling_active;
+ if (sampling_active == 0) {
+ // No sampling is ongoing. Try to get sampled.
+ jbyte result = Atomic::cmpxchg((jbyte)1,
+ &_eden_chunk_sampling_active,
+ (jbyte)0);
+ if (result == 0) {
+ // CAS success. Will take a sample.
+ do_sampling = true;
+ break;
+ }
+ } else {
+ break;
+ }
+ } while (true);
+ if (do_sampling) {
+ // Record a sample. This is the critical section. The contents
+ // of the _eden_chunk_array have to be non-decreasing in the
+ // address order.
+ _eden_chunk_array[_eden_chunk_index] = *_top_addr;
+ assert(_eden_chunk_array[_eden_chunk_index] <= *_end_addr,
+ "Unexpected state of Eden");
+ if (_eden_chunk_index == 0 ||
+ ((_eden_chunk_array[_eden_chunk_index] > _eden_chunk_array[_eden_chunk_index-1]) &&
+ (pointer_delta(_eden_chunk_array[_eden_chunk_index],
+ _eden_chunk_array[_eden_chunk_index-1]) >= CMSSamplingGrain))) {
+ _eden_chunk_index++; // commit sample
+ }
+ assert(_eden_chunk_sampling_active == 1, "Mutual exclusivity");
+ // Indicate that the current sampling has ended and let the next
+ // sampling attempt in.
+ jbyte result = Atomic::cmpxchg((jbyte)0,
+ &_eden_chunk_sampling_active,
+ (jbyte)1);
+ assert(result == 1, "CAS must succeed");
+ }
+ }
+}
+
// Return a thread-local PLAB recording array, as appropriate.
void* CMSCollector::get_data_recorder(int thr_num) {
if (_survivor_plab_array != NULL &&
(CMSPLABRecordAlways ||
(_collectorState > Marking && _collectorState < FinalMarking))) {
@@ -9308,6 +9406,5 @@
default:
ShouldNotReachHere();
}
}
-