// We move that task's local finger along.
_task->move_finger_to(addr);
_task->scan_task_entry(G1TaskQueueEntry::from_oop(cast_to_oop(addr))); // we only partially drain the local queue and global stack
_task->drain_local_queue(true);
_task->drain_global_stack(true);
// if the has_aborted flag has been raised, we need to bail out of // the iteration return !_task->has_aborted();
}
bool G1CMMarkStack::resize(size_t new_capacity) {
assert(is_empty(), "Only resize when stack is empty.");
assert(new_capacity <= _max_chunk_capacity, "Trying to resize stack to " SIZE_FORMAT " chunks when the maximum is " SIZE_FORMAT, new_capacity, _max_chunk_capacity);
if (new_base == NULL) {
log_warning(gc)("Failed to reserve memory for new overflow mark stack with " SIZE_FORMAT " chunks and size " SIZE_FORMAT "B.", new_capacity, new_capacity * sizeof(TaskQueueEntryChunk)); returnfalse;
} // Release old mapping. if (_base != NULL) {
MmapArrayAllocator<TaskQueueEntryChunk>::free(_base, _chunk_capacity);
}
log_debug(gc)("Initialize mark stack with " SIZE_FORMAT " chunks, maximum " SIZE_FORMAT,
initial_chunk_capacity, _max_chunk_capacity);
return resize(initial_chunk_capacity);
}
void G1CMMarkStack::expand() { if (_chunk_capacity == _max_chunk_capacity) {
log_debug(gc)("Can not expand overflow mark stack further, already at maximum capacity of " SIZE_FORMAT " chunks.", _chunk_capacity); return;
}
size_t old_capacity = _chunk_capacity; // Double capacity if possible
size_t new_capacity = MIN2(old_capacity * 2, _max_chunk_capacity);
if (resize(new_capacity)) {
log_debug(gc)("Expanded mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
old_capacity, new_capacity);
} else {
log_warning(gc)("Failed to expand mark stack capacity from " SIZE_FORMAT " to " SIZE_FORMAT " chunks",
old_capacity, new_capacity);
}
}
G1CMMarkStack::TaskQueueEntryChunk* G1CMMarkStack::allocate_new_chunk() { // This dirty read of _hwm is okay because we only ever increase the _hwm in parallel code. // Further this limits _hwm to a value of _chunk_capacity + #threads, avoiding // wraparound of _hwm. if (_hwm >= _chunk_capacity) { return NULL;
}
void G1CMRootMemRegions::add(HeapWord* start, HeapWord* end) {
assert_at_safepoint();
size_t idx = Atomic::fetch_and_add(&_num_root_regions, 1u);
assert(idx < _max_regions, "Trying to add more root MemRegions than there is space " SIZE_FORMAT, _max_regions);
assert(start != NULL && end != NULL && start <= end, "Start (" PTR_FORMAT ") should be less or equal to " "end (" PTR_FORMAT ")", p2i(start), p2i(end));
_root_regions[idx].set_start(start);
_root_regions[idx].set_end(end);
}
const MemRegion* G1CMRootMemRegions::claim_next() { if (_should_abort) { // If someone has set the should_abort flag, we return NULL to // force the caller to bail out of their loop. return NULL;
}
if (_claimed_root_regions >= _num_root_regions) { return NULL;
}
G1ConcurrentMark::G1ConcurrentMark(G1CollectedHeap* g1h,
G1RegionToSpaceMapper* bitmap_storage) : // _cm_thread set inside the constructor
_g1h(g1h),
_mark_bitmap(),
_heap(_g1h->reserved()),
_root_regions(_g1h->max_regions()),
_global_mark_stack(),
// _finger set in set_non_marking_state
_worker_id_offset(G1DirtyCardQueueSet::num_par_ids() + G1ConcRefinementThreads),
_max_num_tasks(MAX2(ConcGCThreads, ParallelGCThreads)), // _num_active_tasks set in set_non_marking_state() // _tasks set inside the constructor
_concurrent_workers = new WorkerThreads("G1 Conc", _max_concurrent_workers);
_concurrent_workers->initialize_workers();
if (!_global_mark_stack.initialize(MarkStackSize, MarkStackSizeMax)) {
vm_exit_during_initialization("Failed to allocate initial concurrent mark overflow mark stack.");
}
// Reset all tasks, since different phases will use different number of active // threads. So, it's easiest to have all of them ready. for (uint i = 0; i < _max_num_tasks; ++i) {
_tasks[i]->reset(mark_bitmap());
}
uint max_reserved_regions = _g1h->max_reserved_regions(); for (uint i = 0; i < max_reserved_regions; i++) {
_top_at_rebuild_starts[i] = NULL;
_region_mark_stats[i].clear();
}
// Expand the marking stack, if we have to and if we can. if (has_overflown()) {
_global_mark_stack.expand();
uint max_reserved_regions = _g1h->max_reserved_regions(); for (uint i = 0; i < max_reserved_regions; i++) {
_region_mark_stats[i].clear_during_overflow();
}
}
clear_has_overflown();
_finger = _heap.start();
for (uint i = 0; i < _max_num_tasks; ++i) {
G1CMTaskQueue* queue = _task_queues->queue(i);
queue->set_empty();
}
}
void G1ConcurrentMark::set_concurrency(uint active_tasks) {
assert(active_tasks <= _max_num_tasks, "we should not have more");
_num_active_tasks = active_tasks; // Need to update the three data structures below according to the // number of active threads for this phase.
_terminator.reset_for_reuse(active_tasks);
_first_overflow_barrier_sync.set_n_workers((int) active_tasks);
_second_overflow_barrier_sync.set_n_workers((int) active_tasks);
}
if (!concurrent) { // At this point we should be in a STW phase, and completed marking.
assert_at_safepoint_on_vm_thread();
assert(out_of_regions(), "only way to get here: _finger: " PTR_FORMAT ", _heap_end: " PTR_FORMAT,
p2i(_finger), p2i(_heap.end()));
}
}
void G1ConcurrentMark::reset_at_marking_complete() { // We set the global marking state to some default values when we're // not doing marking.
reset_marking_for_restart();
_num_active_tasks = 0;
}
G1ConcurrentMark::~G1ConcurrentMark() {
FREE_C_HEAP_ARRAY(HeapWord*, _top_at_rebuild_starts);
FREE_C_HEAP_ARRAY(G1RegionMarkStats, _region_mark_stats); // The G1ConcurrentMark instance is never freed.
ShouldNotReachHere();
}
class G1ClearBitMapTask : public WorkerTask { public: static size_t chunk_size() { return M; }
private: // Heap region closure used for clearing the _mark_bitmap. class G1ClearBitmapHRClosure : public HeapRegionClosure { private:
G1ConcurrentMark* _cm;
G1CMBitMap* _bitmap; bool _suspendible; // If suspendible, do yield checks.
HeapWord* region_clear_limit(HeapRegion* r) { // During a Concurrent Undo Mark cycle, the per region top_at_mark_start and // live_words data are current wrt to the _mark_bitmap. We use this information // to only clear ranges of the bitmap that require clearing. if (is_clear_concurrent_undo()) { // No need to clear bitmaps for empty regions (which includes regions we // did not mark through). if (_cm->live_words(r->hrm_index()) == 0) {
assert(_bitmap->get_next_marked_addr(r->bottom(), r->end()) == r->end(), "Should not have marked bits"); return r->bottom();
}
assert(_bitmap->get_next_marked_addr(r->top_at_mark_start(), r->end()) == r->end(), "Should not have marked bits above tams");
} return r->end();
}
// Repeat the asserts from before the start of the closure. We will do them // as asserts here to minimize their overhead on the product. However, we // will have them as guarantees at the beginning / end of the bitmap // clearing to get some checking in the product.
assert(!suspendible() || _cm->cm_thread()->in_progress(), "invariant");
assert(!suspendible() || !G1CollectedHeap::heap()->collector_state()->mark_or_rebuild_in_progress(), "invariant");
// Abort iteration if necessary. if (has_aborted()) { returntrue;
}
}
assert(cur >= end, "Must have completed iteration over the bitmap for region %u.", r->hrm_index());
r->reset_top_at_mark_start();
returnfalse;
}
};
G1ClearBitmapHRClosure _cl;
HeapRegionClaimer _hr_claimer; bool _suspendible; // If the task is suspendible, workers must join the STS.
log_debug(gc, ergo)("Running %s with %u workers for " SIZE_FORMAT " work units.", cl.name(), num_workers, num_chunks);
workers->run_task(&cl, num_workers);
guarantee(may_yield || cl.is_complete(), "Must have completed iteration when not yielding.");
}
void G1ConcurrentMark::cleanup_for_next_mark() { // Make sure that the concurrent mark thread looks to still be in // the current cycle.
guarantee(cm_thread()->in_progress(), "invariant");
// We are finishing up the current cycle by clearing the next // marking bitmap and getting it ready for the next cycle. During // this time no other cycle can start. So, let's make sure that this // is the case.
guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant");
clear_bitmap(_concurrent_workers, true);
// Repeat the asserts from above.
guarantee(cm_thread()->in_progress(), "invariant");
guarantee(!_g1h->collector_state()->mark_or_rebuild_in_progress(), "invariant");
}
void G1ConcurrentMark::clear_bitmap(WorkerThreads* workers) {
assert_at_safepoint_on_vm_thread(); // To avoid fragmentation the full collection requesting to clear the bitmap // might use fewer workers than available. To ensure the bitmap is cleared // as efficiently as possible the number of active workers are temporarily // increased to include all currently created workers.
WithActiveWorkers update(workers, workers->created_workers());
clear_bitmap(workers, false);
}
class G1PreConcurrentStartTask : public G1BatchedTask { // Reset marking state. class ResetMarkingStateTask; // For each region note start of marking. class NoteStartOfMarkTask;
class G1PreConcurrentStartTask::NoteStartOfMarkTask : public G1AbstractSubTask {
HeapRegionClaimer _claimer; public:
NoteStartOfMarkTask() : G1AbstractSubTask(G1GCPhaseTimes::NoteStartOfMark), _claimer(0) { }
double worker_cost() const override { // The work done per region is very small, therefore we choose this magic number to cap the number // of threads used when there are few regions. constdouble regions_per_thread = 1000; return _claimer.n_regions() / regions_per_thread;
}
SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set(); // This is the start of the marking cycle, we're expected all // threads to have SATB queues with active set to false.
satb_mq_set.set_active_all_threads(true, /* new active value */ false/* expected_active */);
_root_regions.prepare_for_scan();
// update_g1_committed() will be called at the end of an evac pause // when marking is on. So, it's also called at the end of the // concurrent start pause to update the heap end, if the heap expands // during it. No need to call it here.
}
// at this point everyone should have synced up and not be doing any // more work
if (barrier_aborted) { // If the barrier aborted we ignore the overflow condition and // just abort the whole marking phase as quickly as possible. return;
}
}
uint G1ConcurrentMark::calc_active_marking_workers() {
uint result = 0; if (!UseDynamicNumberOfGCThreads || !FLAG_IS_DEFAULT(ConcGCThreads)) {
result = _max_concurrent_workers;
} else {
result =
WorkerPolicy::calc_default_active_workers(_max_concurrent_workers, 1, /* Minimum workers */
_num_concurrent_workers,
Threads::number_of_non_daemon_threads()); // Don't scale the result down by scale_concurrent_workers() because // that scaling has already gone into "_max_concurrent_workers".
}
assert(result > 0 && result <= _max_concurrent_workers, "Calculated number of marking workers must be larger than zero and at most the maximum %u, but is %u",
_max_concurrent_workers, result); return result;
}
void G1ConcurrentMark::scan_root_region(const MemRegion* region, uint worker_id) { #ifdef ASSERT
HeapWord* last = region->last();
HeapRegion* hr = _g1h->heap_region_containing(last);
assert(hr->is_old() || hr->top_at_mark_start() == hr->bottom(), "Root regions must be old or survivor/eden but region %u is %s", hr->hrm_index(), hr->get_type_str());
assert(hr->top_at_mark_start() == region->start(), "MemRegion start should be equal to TAMS"); #endif
class G1CMRootRegionScanTask : public WorkerTask {
G1ConcurrentMark* _cm; public:
G1CMRootRegionScanTask(G1ConcurrentMark* cm) :
WorkerTask("G1 Root Region Scan"), _cm(cm) { }
void work(uint worker_id) {
G1CMRootMemRegions* root_regions = _cm->root_regions(); const MemRegion* region = root_regions->claim_next(); while (region != NULL) {
_cm->scan_root_region(region, worker_id);
region = root_regions->claim_next();
}
}
};
void G1ConcurrentMark::scan_root_regions() { // scan_in_progress() will have been set to true only if there was // at least one root region to scan. So, if it's false, we // should not attempt to do any further work. if (root_regions()->scan_in_progress()) {
assert(!has_aborted(), "Aborting before root region scanning is finished not supported.");
_num_concurrent_workers = MIN2(calc_active_marking_workers(), // We distribute work on a per-region basis, so starting // more threads than that is useless.
root_regions()->num_root_regions());
assert(_num_concurrent_workers <= _max_concurrent_workers, "Maximum number of marking threads exceeded");
G1CMRootRegionScanTask task(this);
log_debug(gc, ergo)("Running %s using %u workers for %u work units.",
task.name(), _num_concurrent_workers, root_regions()->num_root_regions());
_concurrent_workers->run_task(&task, _num_concurrent_workers);
// It's possible that has_aborted() is true here without actually // aborting the survivor scan earlier. This is OK as it's // mainly used for sanity checking.
root_regions()->scan_finished();
}
}
// Setting active workers is not guaranteed since fewer // worker threads may currently exist and more may not be // available.
active_workers = _concurrent_workers->set_active_workers(active_workers);
log_info(gc, task)("Using %u workers of %u for marking", active_workers, _concurrent_workers->max_workers());
// Parallel task terminator is set in "set_concurrency_and_phase()"
set_concurrency_and_phase(active_workers, true/* concurrent */);
// Only check bitmap in Remark, and not at After-Verification because the regions // already have their TAMS'es reset. if (location != VerifyLocation::RemarkAfter) {
verifier->verify_bitmap_clear(true/* above_tams_only */);
}
}
}
class G1UpdateRemSetTrackingBeforeRebuildTask : public WorkerTask {
G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm;
HeapRegionClaimer _hrclaimer;
uint volatile _total_selected_for_rebuild;
G1PrintRegionLivenessInfoClosure _cl;
class G1UpdateRemSetTrackingBeforeRebuild : public HeapRegionClosure {
G1CollectedHeap* _g1h;
G1ConcurrentMark* _cm;
G1PrintRegionLivenessInfoClosure* _cl;
uint _num_regions_selected_for_rebuild; // The number of regions actually selected for rebuild.
// Distribute the given words across the humongous object starting with hr and // note end of marking. void distribute_marked_bytes(HeapRegion* hr, size_t marked_words) {
uint const region_idx = hr->hrm_index();
size_t const obj_size_in_words = cast_to_oop(hr->bottom())->size();
uint const num_regions_in_humongous = (uint)G1CollectedHeap::humongous_obj_size_in_regions(obj_size_in_words);
// "Distributing" zero words means that we only note end of marking for these // regions.
assert(marked_words == 0 || obj_size_in_words == marked_words, "Marked words should either be 0 or the same as humongous object (" SIZE_FORMAT ") but is " SIZE_FORMAT,
obj_size_in_words, marked_words);
for (uint i = region_idx; i < (region_idx + num_regions_in_humongous); i++) {
HeapRegion* const r = _g1h->region_at(i);
size_t const words_to_add = MIN2(HeapRegion::GrainWords, marked_words);
log_trace(gc, marking)("Adding " SIZE_FORMAT " words to humongous region %u (%s)",
words_to_add, i, r->get_type_str());
add_marked_bytes_and_note_end(r, words_to_add * HeapWordSize);
marked_words -= words_to_add;
}
assert(marked_words == 0,
SIZE_FORMAT " words left after distributing space across %u regions",
marked_words, num_regions_in_humongous);
}
void update_marked_bytes(HeapRegion* hr) {
uint const region_idx = hr->hrm_index();
size_t const marked_words = _cm->live_words(region_idx); // The marking attributes the object's size completely to the humongous starts // region. We need to distribute this value across the entire set of regions a // humongous object spans. if (hr->is_humongous()) {
assert(hr->is_starts_humongous() || marked_words == 0, "Should not have marked words " SIZE_FORMAT " in non-starts humongous region %u (%s)",
marked_words, region_idx, hr->get_type_str()); if (hr->is_starts_humongous()) {
distribute_marked_bytes(hr, marked_words);
}
} else {
log_trace(gc, marking)("Adding " SIZE_FORMAT " words to region %u (%s)", marked_words, region_idx, hr->get_type_str());
add_marked_bytes_and_note_end(hr, _cm->live_bytes(region_idx));
}
}
virtualbool do_heap_region(HeapRegion* r) { // Update the remset tracking state from updating to complete // if remembered sets have been rebuilt.
_g1h->policy()->remset_tracker()->update_after_rebuild(r); returnfalse;
}
};
// If a full collection has happened, we should not continue. However we might // have ended up here as the Remark VM operation has been scheduled already. if (has_aborted()) { return;
}
boolconst mark_finished = !has_overflown(); if (mark_finished) {
weak_refs_work();
SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set(); // We're done with marking. // This is the end of the marking cycle, we're expected all // threads to have SATB queues with active set to true.
satb_mq_set.set_active_all_threads(false, /* new active value */ true/* expected_active */);
// All marking completed. Check bitmap now as we will start to reset TAMSes // in parallel below so that we can not do this in the After-Remark verification.
_g1h->verifier()->verify_bitmap_clear(true/* above_tams_only */);
{
GCTraceTime(Debug, gc, phases) debug("Update Remembered Set Tracking Before Rebuild", _gc_timer_cm);
G1UpdateRemSetTrackingBeforeRebuildTask cl(_g1h, this, num_workers);
log_debug(gc,ergo)("Running %s using %u workers for %u regions in heap", cl.name(), num_workers, _g1h->num_regions());
_g1h->workers()->run_task(&cl, num_workers);
log_debug(gc, remset, tracking)("Remembered Set Tracking update regions total %u, selected %u",
_g1h->num_regions(), cl.total_selected_for_rebuild());
class G1ReclaimEmptyRegionsTask : public WorkerTask { // Per-region work during the Cleanup pause. class G1ReclaimEmptyRegionsClosure : public HeapRegionClosure {
G1CollectedHeap* _g1h;
size_t _freed_bytes;
FreeRegionList* _local_cleanup_list;
uint _old_regions_removed;
uint _archive_regions_removed;
uint _humongous_regions_removed;
// Now update the old/archive/humongous region sets
_g1h->remove_from_old_gen_sets(cl.old_regions_removed(),
cl.archive_regions_removed(),
cl.humongous_regions_removed());
{
MutexLocker x(ParGCRareEvent_lock, Mutex::_no_safepoint_check_flag);
_g1h->decrement_summary_bytes(cl.freed_bytes());
void G1ConcurrentMark::reclaim_empty_regions() {
WorkerThreads* workers = _g1h->workers();
FreeRegionList empty_regions_list("Empty Regions After Mark List");
if (!empty_regions_list.is_empty()) {
log_debug(gc)("Reclaimed %u empty regions", empty_regions_list.length()); // Now print the empty regions list.
_g1h->hr_printer()->cleanup(&empty_regions_list); // And actually make them available.
_g1h->prepend_to_freelist(&empty_regions_list);
}
}
// Cleanup will have freed any regions completely full of garbage. // Update the soft reference policy with the new heap occupancy.
Universe::heap()->update_capacity_and_used_at_gc();
// We reclaimed old regions so we should calculate the sizes to make // sure we update the old gen/space data.
_g1h->monitoring_support()->update_sizes();
}
if (needs_remembered_set_rebuild()) { // Update the remset tracking information as well as marking all regions // as fully parsable.
GCTraceTime(Debug, gc, phases) debug("Update Remembered Set Tracking After Rebuild", _gc_timer_cm);
G1UpdateRegionsAfterRebuild cl(_g1h);
_g1h->heap_region_iterate(&cl);
} else {
log_debug(gc, phases)("No Remembered Sets to update after rebuild");
}
// We need to make this be a "collection" so any collection pause that // races with it goes around and waits for Cleanup to finish.
_g1h->increment_total_collections();
// 'Keep Alive' oop closure used by both serial parallel reference processing. // Uses the G1CMTask associated with a worker thread (for serial reference // processing the G1CMTask for worker 0 is used) to preserve (mark) and // trace referent objects. // // Using the G1CMTask and embedded local queues avoids having the worker // threads operating on the global mark stack. This reduces the risk // of overflowing the stack - which we would rather avoid at this late // state. Also using the tasks' local queues removes the potential // of the workers interfering with each other that could occur if // operating on the global stack.
class G1CMKeepAliveAndDrainClosure : public OopClosure {
G1ConcurrentMark* _cm;
G1CMTask* _task;
uint _ref_counter_limit;
uint _ref_counter; bool _is_serial; public:
G1CMKeepAliveAndDrainClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
_cm(cm), _task(task), _ref_counter_limit(G1RefProcDrainInterval),
_ref_counter(_ref_counter_limit), _is_serial(is_serial) {
assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
}
template <class T> void do_oop_work(T* p) { if (_cm->has_overflown()) { return;
} if (!_task->deal_with_reference(p)) { // We did not add anything to the mark bitmap (or mark stack), so there is // no point trying to drain it. return;
}
_ref_counter--;
if (_ref_counter == 0) { // We have dealt with _ref_counter_limit references, pushing them // and objects reachable from them on to the local stack (and // possibly the global stack). Call G1CMTask::do_marking_step() to // process these entries. // // We call G1CMTask::do_marking_step() in a loop, which we'll exit if // there's nothing more to do (i.e. we're done with the entries that // were pushed as a result of the G1CMTask::deal_with_reference() calls // above) or we overflow. // // Note: G1CMTask::do_marking_step() can set the G1CMTask::has_aborted() // flag while there may still be some work to do. (See the comment at // the beginning of G1CMTask::do_marking_step() for those conditions - // one of which is reaching the specified time target.) It is only // when G1CMTask::do_marking_step() returns without setting the // has_aborted() flag that the marking step has completed. do { double mark_step_duration_ms = G1ConcMarkStepDurationMillis;
_task->do_marking_step(mark_step_duration_ms, false/* do_termination */,
_is_serial);
} while (_task->has_aborted() && !_cm->has_overflown());
_ref_counter = _ref_counter_limit;
}
}
};
// 'Drain' oop closure used by both serial and parallel reference processing. // Uses the G1CMTask associated with a given worker thread (for serial // reference processing the G1CMtask for worker 0 is used). Calls the // do_marking_step routine, with an unbelievably large timeout value, // to drain the marking data structures of the remaining entries // added by the 'keep alive' oop closure above.
class G1CMDrainMarkingStackClosure : public VoidClosure {
G1ConcurrentMark* _cm;
G1CMTask* _task; bool _is_serial; public:
G1CMDrainMarkingStackClosure(G1ConcurrentMark* cm, G1CMTask* task, bool is_serial) :
_cm(cm), _task(task), _is_serial(is_serial) {
assert(!_is_serial || _task->worker_id() == 0, "only task 0 for serial code");
}
void do_void() { do { // We call G1CMTask::do_marking_step() to completely drain the local // and global marking stacks of entries pushed by the 'keep alive' // oop closure (an instance of G1CMKeepAliveAndDrainClosure above). // // G1CMTask::do_marking_step() is called in a loop, which we'll exit // if there's nothing more to do (i.e. we've completely drained the // entries that were pushed as a result of applying the 'keep alive' // closure to the entries on the discovered ref lists) or we overflow // the global marking stack. // // Note: G1CMTask::do_marking_step() can set the G1CMTask::has_aborted() // flag while there may still be some work to do. (See the comment at // the beginning of G1CMTask::do_marking_step() for those conditions - // one of which is reaching the specified time target.) It is only // when G1CMTask::do_marking_step() returns without setting the // has_aborted() flag that the marking step has completed.
_task->do_marking_step(1000000000.0/* something very large */, true/* do_termination */,
_is_serial);
} while (_task->has_aborted() && !_cm->has_overflown());
}
};
class G1CMRefProcProxyTask : public RefProcProxyTask {
G1CollectedHeap& _g1h;
G1ConcurrentMark& _cm;
void prepare_run_task_hook() override { // We need to reset the concurrency level before each // proxy task execution, so that the termination protocol // and overflow handling in G1CMTask::do_marking_step() knows // how many workers to wait for.
_cm.set_concurrency(_queue_count);
}
};
ReferenceProcessor* rp = _g1h->ref_processor_cm();
// See the comment in G1CollectedHeap::ref_processing_init() // about how reference processing currently works in G1.
assert(_global_mark_stack.is_empty(), "mark stack should be empty");
// We need at least one active thread. If reference processing // is not multi-threaded we use the current (VMThread) thread, // otherwise we use the workers from the G1CollectedHeap and // we utilize all the worker threads we can.
uint active_workers = (ParallelRefProcEnabled ? _g1h->workers()->active_workers() : 1U);
active_workers = clamp(active_workers, 1u, _max_num_tasks);
// Set the degree of MT processing here. If the discovery was done MT, // the number of threads involved during discovery could differ from // the number of active workers. This is OK as long as the discovered // Reference lists are balanced (see balance_all_queues() and balance_queues()).
rp->set_active_mt_degree(active_workers);
// Process the weak references. const ReferenceProcessorStats& stats = rp->process_discovered_references(task, pt);
_gc_tracer_cm->report_gc_reference_stats(stats);
pt.print_all_references();
// The do_oop work routines of the keep_alive and drain_marking_stack // oop closures will set the has_overflown flag if we overflow the // global marking stack.
assert(has_overflown() || _global_mark_stack.is_empty(), "Mark stack should be empty (unless it has overflown)");
if (has_overflown()) { // We can not trust g1_is_alive and the contents of the heap if the marking stack // overflowed while processing references. Exit the VM.
fatal("Overflow during reference processing, can not continue. Current mark stack depth: "
SIZE_FORMAT ", MarkStackSize: " SIZE_FORMAT ", MarkStackSizeMax: " SIZE_FORMAT ". " "Please increase MarkStackSize and/or MarkStackSizeMax and restart.",
_global_mark_stack.size(), MarkStackSize, MarkStackSizeMax); return;
}
assert(_global_mark_stack.is_empty(), "Marking should have completed");
void G1ConcurrentMark::report_object_count(bool mark_completed) { // Depending on the completion of the marking liveness needs to be determined // using either the bitmap or after the cycle using the scrubbing information. if (mark_completed) {
G1ObjectCountIsAliveClosure is_alive(_g1h);
_gc_tracer_cm->report_object_count_after_gc(&is_alive);
} else {
G1CMIsAliveClosure is_alive(_g1h);
_gc_tracer_cm->report_object_count_after_gc(&is_alive);
}
}
// Closure for marking entries in SATB buffers. class G1CMSATBBufferClosure : public SATBBufferClosure { private:
G1CMTask* _task;
G1CollectedHeap* _g1h;
// This is very similar to G1CMTask::deal_with_reference, but with // more relaxed requirements for the argument, so this must be more // circumspect about treating the argument as an object. void do_entry(void* entry) const {
_task->increment_refs_reached();
oop const obj = cast_to_oop(entry);
_task->make_reference_grey(obj);
}
void do_thread(Thread* thread) { if (thread->claim_threads_do(true, _claim_token)) { // Transfer any partial buffer to the qset for completed buffer processing.
_qset.flush_queue(G1ThreadLocalData::satb_mark_queue(thread)); if (thread->is_Java_thread()) { // In theory it should not be necessary to explicitly walk the nmethods to find roots for concurrent marking // however the liveness of oops reachable from nmethods have very complex lifecycles: // * Alive if on the stack of an executing method // * Weakly reachable otherwise // Some objects reachable from nmethods, such as the class loader (or klass_holder) of the receiver should be // live by the SATB invariant but other oops recorded in nmethods may behave differently.
JavaThread::cast(thread)->nmethods_do(&_code_cl);
}
}
}
};
do {
task->do_marking_step(1000000000.0/* something very large */, true/* do_termination */, false/* is_serial */);
} while (task->has_aborted() && !_cm->has_overflown()); // If we overflow, then we do not want to restart. We instead // want to abort remark and do concurrent marking again.
task->record_end_time();
}
// this is remark, so we'll use up all active threads
uint active_workers = _g1h->workers()->active_workers();
set_concurrency_and_phase(active_workers, false/* concurrent */); // Leave _parallel_marking_threads at it's // value originally calculated in the G1ConcurrentMark // constructor and pass values of the active workers // through the task.
{
StrongRootsScope srs(active_workers);
G1CMRemarkTask remarkTask(this, active_workers); // We will start all available threads, even if we decide that the // active_workers will be fewer. The extra ones will just bail out // immediately.
_g1h->workers()->run_task(&remarkTask);
}
while (finger < _heap.end()) {
assert(_g1h->is_in_reserved(finger), "invariant");
HeapRegion* curr_region = _g1h->heap_region_containing_or_null(finger); // Make sure that the reads below do not float before loading curr_region.
OrderAccess::loadload(); // Above heap_region_containing may return NULL as we always scan claim // until the end of the heap. In this case, just jump to the next region.
HeapWord* end = curr_region != nullptr ? curr_region->end() : finger + HeapRegion::GrainWords;
// Is the gap between reading the finger and doing the CAS too long?
HeapWord* res = Atomic::cmpxchg(&_finger, finger, end); if (res == finger && curr_region != nullptr) { // we succeeded
HeapWord* bottom = curr_region->bottom();
HeapWord* limit = curr_region->top_at_mark_start();
// notice that _finger == end cannot be guaranteed here since, // someone else might have moved the finger even further
assert(_finger >= end, "the finger should have moved forward");
if (limit > bottom) {
assert(!curr_region->is_closed_archive(), "CA regions should be skipped"); return curr_region;
} else {
assert(limit == bottom, "the region limit should be at bottom"); // we return NULL and the caller should try calling // claim_region() again. return nullptr;
}
} else {
assert(_finger > finger, "the finger should have moved forward"); // read it again
finger = _finger;
}
}
return nullptr;
}
#ifndef PRODUCT class VerifyNoCSetOops {
G1CollectedHeap* _g1h; constchar* _phase; int _info;
public:
VerifyNoCSetOops(constchar* phase, int info = -1) :
_g1h(G1CollectedHeap::heap()),
_phase(phase),
_info(info)
{ }
voidoperator()(G1TaskQueueEntry task_entry) const { if (task_entry.is_array_slice()) {
guarantee(_g1h->is_in_reserved(task_entry.slice()), "Slice " PTR_FORMAT " must be in heap.", p2i(task_entry.slice())); return;
}
guarantee(oopDesc::is_oop(task_entry.obj()), "Non-oop " PTR_FORMAT ", phase: %s, info: %d",
p2i(task_entry.obj()), _phase, _info);
HeapRegion* r = _g1h->heap_region_containing(task_entry.obj());
guarantee(!(r->in_collection_set() || r->has_index_in_opt_cset()), "obj " PTR_FORMAT " from %s (%d) in region %u in (optional) collection set",
p2i(task_entry.obj()), _phase, _info, r->hrm_index());
}
};
void G1ConcurrentMark::verify_no_collection_set_oops() {
assert(SafepointSynchronize::is_at_safepoint(), "should be at a safepoint"); if (!_g1h->collector_state()->mark_or_rebuild_in_progress()) { return;
}
// Verify entries on the global mark stack
_global_mark_stack.iterate(VerifyNoCSetOops("Stack"));
// Verify entries on the task queues for (uint i = 0; i < _max_num_tasks; ++i) {
G1CMTaskQueue* queue = _task_queues->queue(i);
queue->iterate(VerifyNoCSetOops("Queue", i));
}
// Verify the global finger
HeapWord* global_finger = finger(); if (global_finger != nullptr && global_finger < _heap.end()) { // Since we always iterate over all regions, we might get a nullptr HeapRegion // here.
HeapRegion* global_hr = _g1h->heap_region_containing_or_null(global_finger);
guarantee(global_hr == nullptr || global_finger == global_hr->bottom(), "global finger: " PTR_FORMAT " region: " HR_FORMAT,
p2i(global_finger), HR_FORMAT_PARAMS(global_hr));
}
// Verify the task fingers
assert(_num_concurrent_workers <= _max_num_tasks, "sanity"); for (uint i = 0; i < _num_concurrent_workers; ++i) {
G1CMTask* task = _tasks[i];
HeapWord* task_finger = task->finger(); if (task_finger != nullptr && task_finger < _heap.end()) { // See above note on the global finger verification.
HeapRegion* r = _g1h->heap_region_containing_or_null(task_finger);
guarantee(r == nullptr || task_finger == r->bottom() ||
!r->in_collection_set() || !r->has_index_in_opt_cset(), "task finger: " PTR_FORMAT " region: " HR_FORMAT,
p2i(task_finger), HR_FORMAT_PARAMS(r));
}
}
} #endif// PRODUCT
void G1ConcurrentMark::rebuild_and_scrub() { if (!needs_remembered_set_rebuild()) {
log_debug(gc, marking)("Skipping Remembered Set Rebuild. No regions selected for rebuild, will only scrub");
}
void G1ConcurrentMark::print_stats() { if (!log_is_enabled(Debug, gc, stats)) { return;
}
log_debug(gc, stats)("---------------------------------------------------------------------"); for (size_t i = 0; i < _num_active_tasks; ++i) {
_tasks[i]->print_stats();
log_debug(gc, stats)("---------------------------------------------------------------------");
}
}
bool G1ConcurrentMark::concurrent_cycle_abort() { // If we start the compaction before the CM threads finish // scanning the root regions we might trip them over as we'll // be moving objects / updating references. So let's wait until // they are done. By telling them to abort, they should complete // early.
root_regions()->abort();
root_regions()->wait_until_scan_finished();
// We haven't started a concurrent cycle no need to do anything; we might have // aborted the marking because of shutting down though. In this case the marking // might have already completed the abort (leading to in_progress() below to // return false), however this still left marking state particularly in the // shared marking bitmap that must be cleaned up. // If there are multiple full gcs during shutdown we do this work repeatedly for // nothing, but this situation should be extremely rare (a full gc after shutdown // has been signalled is already rare), and this work should be negligible compared // to actual full gc work. if (!cm_thread()->in_progress() && !_g1h->concurrent_mark_is_terminating()) { returnfalse;
}
// Empty mark stack
reset_marking_for_restart(); for (uint i = 0; i < _max_num_tasks; ++i) {
_tasks[i]->clear_region_fields();
}
abort_marking_threads();
SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set();
satb_mq_set.abandon_partial_marking(); // This can be called either during or outside marking, we'll read // the expected_active value from the SATB queue set.
satb_mq_set.set_active_all_threads(false, /* new active value */
satb_mq_set.is_active() /* expected_active */); returntrue;
}
}
print_ms_time_info(" ", "cleanups", _cleanup_times);
log.trace(" Finalize live data total time = %8.2f s (avg = %8.2f ms).",
_total_cleanup_time, (_cleanup_times.num() > 0 ? _total_cleanup_time * 1000.0 / (double)_cleanup_times.num() : 0.0));
log.trace(" Total stop_world time = %8.2f s.",
(_init_times.sum() + _remark_times.sum() + _cleanup_times.sum())/1000.0);
log.trace(" Total concurrent time = %8.2f s (%8.2f s marking).",
cm_thread()->vtime_accum(), cm_thread()->vtime_mark_accum());
}
if (limit == bottom) { // The region was collected underneath our feet. // We set the finger to bottom to ensure that the bitmap // iteration that will follow this will not do anything. // (this is not a condition that holds when we set the region up, // as the region is not supposed to be empty in the first place)
_finger = bottom;
} elseif (limit >= _region_limit) {
assert(limit >= _finger, "peace of mind");
} else {
assert(limit < _region_limit, "only way to get here"); // This can happen under some pretty unusual circumstances. An // evacuation pause empties the region underneath our feet (TAMS // at bottom). We then do some allocation in the region (TAMS // stays at bottom), followed by the region being used as a GC // alloc region (TAMS will move to top() and the objects // originally below it will be greyed). All objects now marked in // the region are explicitly greyed, if below the global finger, // and we do not need in fact to scan anything else. So, we simply // set _finger to be limit to ensure that the bitmap iteration // doesn't do anything.
_finger = limit;
}
void G1CMTask::clear_region_fields() { // Values for these three fields that indicate that we're not // holding on to a region.
_curr_region = NULL;
_finger = NULL;
_region_limit = NULL;
}
bool G1CMTask::should_exit_termination() { if (!regular_clock_call()) { returntrue;
}
// This is called when we are in the termination protocol. We should // quit if, for some reason, this task wants to abort or the global // stack is not empty (this means that we can get work from it). return !_cm->mark_stack_empty() || has_aborted();
}
void G1CMTask::reached_limit() {
assert(_words_scanned >= _words_scanned_limit ||
_refs_reached >= _refs_reached_limit , "shouldn't have been called otherwise");
abort_marking_if_regular_check_fail();
}
bool G1CMTask::regular_clock_call() { if (has_aborted()) { returnfalse;
}
// First, we need to recalculate the words scanned and refs reached // limits for the next clock call.
recalculate_limits();
// During the regular clock call we do the following
// (1) If an overflow has been flagged, then we abort. if (_cm->has_overflown()) { returnfalse;
}
// If we are not concurrent (i.e. we're doing remark) we don't need // to check anything else. The other steps are only needed during // the concurrent marking phase. if (!_cm->concurrent()) { returntrue;
}
// (2) If marking has been aborted for Full GC, then we also abort. if (_cm->has_aborted()) { returnfalse;
}
// (4) We check whether we should yield. If we have to, then we abort. if (SuspendibleThreadSet::should_yield()) { // We should yield. To do this we abort the task. The caller is // responsible for yielding. returnfalse;
}
// (5) We check whether we've reached our time quota. If we have, // then we abort. double elapsed_time_ms = curr_time_ms - _start_time_ms; if (elapsed_time_ms > _time_target_ms) {
_has_timed_out = true; returnfalse;
}
// (6) Finally, we check whether there are enough completed STAB // buffers available for processing. If there are, we abort.
SATBMarkQueueSet& satb_mq_set = G1BarrierSet::satb_mark_queue_set(); if (!_draining_satb_buffers && satb_mq_set.process_completed_buffers()) { // we do need to process SATB buffers, we'll abort and restart // the marking task to do so returnfalse;
} returntrue;
}
void G1CMTask::decrease_limits() { // This is called when we believe that we're going to do an infrequent // operation which will increase the per byte scanned cost (i.e. move // entries to/from the global stack). It basically tries to decrease the // scanning limit so that the clock is called earlier.
void G1CMTask::move_entries_to_global_stack() { // Local array where we'll store the entries that will be popped // from the local queue.
G1TaskQueueEntry buffer[G1CMMarkStack::EntriesPerChunk];
size_t n = 0;
G1TaskQueueEntry task_entry; while (n < G1CMMarkStack::EntriesPerChunk && _task_queue->pop_local(task_entry)) {
buffer[n] = task_entry;
++n;
} if (n < G1CMMarkStack::EntriesPerChunk) {
buffer[n] = G1TaskQueueEntry();
}
if (n > 0) { if (!_cm->mark_stack_push(buffer)) {
set_has_aborted();
}
}
// This operation was quite expensive, so decrease the limits.
decrease_limits();
}
bool G1CMTask::get_entries_from_global_stack() { // Local array where we'll store the entries that will be popped // from the global stack.
G1TaskQueueEntry buffer[G1CMMarkStack::EntriesPerChunk];
if (!_cm->mark_stack_pop(buffer)) { returnfalse;
}
// We did actually pop at least one entry. for (size_t i = 0; i < G1CMMarkStack::EntriesPerChunk; ++i) {
G1TaskQueueEntry task_entry = buffer[i]; if (task_entry.is_null()) { break;
}
assert(task_entry.is_array_slice() || oopDesc::is_oop(task_entry.obj()), "Element " PTR_FORMAT " must be an array slice or oop", p2i(task_entry.obj())); bool success = _task_queue->push(task_entry); // We only call this when the local queue is empty or under a // given target limit. So, we do not expect this push to fail.
assert(success, "invariant");
}
// This operation was quite expensive, so decrease the limits
decrease_limits(); returntrue;
}
void G1CMTask::drain_local_queue(bool partially) { if (has_aborted()) { return;
}
// Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out // of things to do) or totally (at the very end).
size_t target_size; if (partially) {
target_size = MIN2((size_t)_task_queue->max_elems()/3, (size_t)GCDrainStackTargetSize);
} else {
target_size = 0;
}
if (_task_queue->size() > target_size) {
G1TaskQueueEntry entry; bool ret = _task_queue->pop_local(entry); while (ret) {
scan_task_entry(entry); if (_task_queue->size() <= target_size || has_aborted()) {
ret = false;
} else {
ret = _task_queue->pop_local(entry);
}
}
}
}
void G1CMTask::drain_global_stack(bool partially) { if (has_aborted()) { return;
}
// We have a policy to drain the local queue before we attempt to // drain the global stack.
assert(partially || _task_queue->size() == 0, "invariant");
// Decide what the target size is, depending whether we're going to // drain it partially (so that other tasks can steal if they run out // of things to do) or totally (at the very end). // Notice that when draining the global mark stack partially, due to the racyness // of the mark stack size update we might in fact drop below the target. But, // this is not a problem. // In case of total draining, we simply process until the global mark stack is // totally empty, disregarding the size counter. if (partially) {
size_t const target_size = _cm->partial_mark_stack_size_target(); while (!has_aborted() && _cm->mark_stack_size() > target_size) { if (get_entries_from_global_stack()) {
drain_local_queue(partially);
}
}
} else { while (!has_aborted() && get_entries_from_global_stack()) {
drain_local_queue(partially);
}
}
}
// SATB Queue has several assumptions on whether to call the par or // non-par versions of the methods. this is why some of the code is // replicated. We should really get rid of the single-threaded version // of the code to simplify things. void G1CMTask::drain_satb_buffers() { if (has_aborted()) { return;
}
// We set this so that the regular clock knows that we're in the // middle of draining buffers and doesn't set the abort flag when it // notices that SATB buffers are available for draining. It'd be // very counter productive if it did that. :-)
_draining_satb_buffers = true;
// This keeps claiming and applying the closure to completed buffers // until we run out of buffers or we need to abort. while (!has_aborted() &&
satb_mq_set.apply_closure_to_completed_buffer(&satb_cl)) {
abort_marking_if_regular_check_fail();
}
// Can't assert qset is empty here, even if not aborted. If concurrent, // some other thread might be adding to the queue. If not concurrent, // some other thread might have won the race for the last buffer, but // has not yet decremented the count.
_draining_satb_buffers = false;
// again, this was a potentially expensive operation, decrease the // limits to get the regular clock call early
decrease_limits();
}
// If do_stealing is true then do_marking_step will attempt to // steal work from the other G1CMTasks. It only makes sense to // enable stealing when the termination protocol is enabled // and do_marking_step() is not being called serially. bool do_stealing = do_termination && !is_serial;
// set up the variables that are used in the work-based scheme to // call the regular clock method
_words_scanned = 0;
_refs_reached = 0;
recalculate_limits();
// Set up the bitmap and oop closures. Anything that uses them is // eventually called from this method, so it is OK to allocate these // statically.
G1CMBitMapClosure bitmap_closure(this, _cm);
G1CMOopClosure cm_oop_closure(_g1h, this);
set_cm_oop_closure(&cm_oop_closure);
if (_cm->has_overflown()) { // This can happen if the mark stack overflows during a GC pause // and this task, after a yield point, restarts. We have to abort // as we need to get into the overflow protocol which happens // right at the end of this task.
set_has_aborted();
}
// First drain any available SATB buffers. After this, we will not // look at SATB buffers before the next invocation of this method. // If enough completed SATB buffers are queued up, the regular clock // will abort this task so that it restarts.
drain_satb_buffers(); // ...then partially drain the local queue and the global stack
drain_local_queue(true);
drain_global_stack(true);
do { if (!has_aborted() && _curr_region != NULL) { // This means that we're already holding on to a region.
assert(_finger != NULL, "if region is not NULL, then the finger " "should not be NULL either");
// We might have restarted this task after an evacuation pause // which might have evacuated the region we're holding on to // underneath our feet. Let's read its limit again to make sure // that we do not iterate over a region of the heap that // contains garbage (update_region_limit() will also move // _finger to the start of the region if it is found empty).
update_region_limit(); // We will start from _finger not from the start of the region, // as we might be restarting this task after aborting half-way // through scanning this region. In this case, _finger points to // the address where we last found a marked object. If this is a // fresh region, _finger points to start().
MemRegion mr = MemRegion(_finger, _region_limit);
assert(!_curr_region->is_humongous() || mr.start() == _curr_region->bottom(), "humongous regions should go around loop once only");
// Some special cases: // If the memory region is empty, we can just give up the region. // If the current region is humongous then we only need to check // the bitmap for the bit associated with the start of the object, // scan the object if it's live, and give up the region. // Otherwise, let's iterate over the bitmap of the part of the region // that is left. // If the iteration is successful, give up the region. if (mr.is_empty()) {
giveup_current_region();
abort_marking_if_regular_check_fail();
} elseif (_curr_region->is_humongous() && mr.start() == _curr_region->bottom()) { if (_mark_bitmap->is_marked(mr.start())) { // The object is marked - apply the closure
bitmap_closure.do_addr(mr.start());
} // Even if this task aborted while scanning the humongous object // we can (and should) give up the current region.
giveup_current_region();
abort_marking_if_regular_check_fail();
} elseif (_mark_bitmap->iterate(&bitmap_closure, mr)) {
giveup_current_region();
abort_marking_if_regular_check_fail();
} else {
assert(has_aborted(), "currently the only way to do so"); // The only way to abort the bitmap iteration is to return // false from the do_bit() method. However, inside the // do_bit() method we move the _finger to point to the // object currently being looked at. So, if we bail out, we // have definitely set _finger to something non-null.
assert(_finger != NULL, "invariant");
// Region iteration was actually aborted. So now _finger // points to the address of the object we last scanned. If we // leave it there, when we restart this task, we will rescan // the object. It is easy to avoid this. We move the finger by // enough to point to the next possible object header.
assert(_finger < _region_limit, "invariant");
HeapWord* const new_finger = _finger + cast_to_oop(_finger)->size(); // Check if bitmap iteration was aborted while scanning the last object if (new_finger >= _region_limit) {
giveup_current_region();
} else {
move_finger_to(new_finger);
}
}
} // At this point we have either completed iterating over the // region we were holding on to, or we have aborted.
// We then partially drain the local queue and the global stack. // (Do we really need this?)
drain_local_queue(true);
drain_global_stack(true);
// Read the note on the claim_region() method on why it might // return NULL with potentially more regions available for // claiming and why we have to check out_of_regions() to determine // whether we're done or not. while (!has_aborted() && _curr_region == NULL && !_cm->out_of_regions()) { // We are going to try to claim a new region. We should have // given up on the previous one. // Separated the asserts so that we know which one fires.
assert(_curr_region == NULL, "invariant");
assert(_finger == NULL, "invariant");
assert(_region_limit == NULL, "invariant");
HeapRegion* claimed_region = _cm->claim_region(_worker_id); if (claimed_region != NULL) { // Yes, we managed to claim one
setup_for_region(claimed_region);
assert(_curr_region == claimed_region, "invariant");
} // It is important to call the regular clock here. It might take // a while to claim a region if, for example, we hit a large // block of empty regions. So we need to call the regular clock // method once round the loop to make sure it's called // frequently enough.
abort_marking_if_regular_check_fail();
}
if (!has_aborted() && _curr_region == NULL) {
assert(_cm->out_of_regions(), "at this point we should be out of regions");
}
} while ( _curr_region != NULL && !has_aborted());
if (!has_aborted()) { // We cannot check whether the global stack is empty, since other // tasks might be pushing objects to it concurrently.
assert(_cm->out_of_regions(), "at this point we should be out of regions"); // Try to reduce the number of available SATB buffers so that // remark has less work to do.
drain_satb_buffers();
}
// Since we've done everything else, we can now totally drain the // local queue and global stack.
drain_local_queue(false);
drain_global_stack(false);
// Attempt at work stealing from other task's queues. if (do_stealing && !has_aborted()) { // We have not aborted. This means that we have finished all that // we could. Let's try to do some stealing...
// We cannot check whether the global stack is empty, since other // tasks might be pushing objects to it concurrently.
assert(_cm->out_of_regions() && _task_queue->size() == 0, "only way to reach here"); while (!has_aborted()) {
G1TaskQueueEntry entry; if (_cm->try_stealing(_worker_id, entry)) {
scan_task_entry(entry);
// And since we're towards the end, let's totally drain the // local queue and global stack.
drain_local_queue(false);
drain_global_stack(false);
} else { break;
}
}
}
// We still haven't aborted. Now, let's try to get into the // termination protocol. if (do_termination && !has_aborted()) { // We cannot check whether the global stack is empty, since other // tasks might be concurrently pushing objects on it. // Separated the asserts so that we know which one fires.
assert(_cm->out_of_regions(), "only way to reach here");
assert(_task_queue->size() == 0, "only way to reach here");
_termination_start_time_ms = os::elapsedVTime() * 1000.0;
// The G1CMTask class also extends the TerminatorTerminator class, // hence its should_exit_termination() method will also decide // whether to exit the termination protocol or not. bool finished = (is_serial ||
_cm->terminator()->offer_termination(this)); double termination_end_time_ms = os::elapsedVTime() * 1000.0;
_termination_time_ms +=
termination_end_time_ms - _termination_start_time_ms;
if (finished) { // We're all done.
// We can now guarantee that the global stack is empty, since // all other tasks have finished. We separated the guarantees so // that, if a condition is false, we can immediately find out // which one.
guarantee(_cm->out_of_regions(), "only way to reach here");
guarantee(_cm->mark_stack_empty(), "only way to reach here");
guarantee(_task_queue->size() == 0, "only way to reach here");
guarantee(!_cm->has_overflown(), "only way to reach here");
guarantee(!has_aborted(), "should never happen if termination has completed");
} else { // Apparently there's more work to do. Let's abort this task. It // will restart it and we can hopefully find more things to do.
set_has_aborted();
}
}
// Mainly for debugging purposes to make sure that a pointer to the // closure which was statically allocated in this frame doesn't // escape it by accident.
set_cm_oop_closure(NULL); double end_time_ms = os::elapsedVTime() * 1000.0; double elapsed_time_ms = end_time_ms - _start_time_ms; // Update the step history.
_step_times_ms.add(elapsed_time_ms);
if (has_aborted()) { // The task was aborted for some reason. if (_has_timed_out) { double diff_ms = elapsed_time_ms - _time_target_ms; // Keep statistics of how well we did with respect to hitting // our target only if we actually timed out (if we aborted for // other reasons, then the results might get skewed).
_marking_step_diff_ms.add(diff_ms);
}
if (_cm->has_overflown()) { // This is the interesting one. We aborted because a global // overflow was raised. This means we have to restart the // marking phase and start iterating over regions. However, in // order to do this we have to make sure that all tasks stop // what they are doing and re-initialize in a safe manner. We // will achieve this with the use of two barrier sync points.
if (!is_serial) { // We only need to enter the sync barrier if being called // from a parallel context
_cm->enter_first_sync_barrier(_worker_id);
// When we exit this sync barrier we know that all tasks have // stopped doing marking work. So, it's now safe to // re-initialize our data structures.
}
clear_region_fields();
flush_mark_stats_cache();
if (!is_serial) { // If we're executing the concurrent phase of marking, reset the marking // state; otherwise the marking state is reset after reference processing, // during the remark pause. // If we reset here as a result of an overflow during the remark we will // see assertion failures from any subsequent set_concurrency_and_phase() // calls. if (_cm->concurrent() && _worker_id == 0) { // Worker 0 is responsible for clearing the global data structures because // of an overflow. During STW we should not clear the overflow flag (in // G1ConcurrentMark::reset_marking_state()) since we rely on it being true when we exit // method to abort the pause and restart concurrent marking.
_cm->reset_marking_for_restart();
log_info(gc, marking)("Concurrent Mark reset for overflow");
}
// ...and enter the second barrier.
_cm->enter_second_sync_barrier(_worker_id);
} // At this point, if we're during the concurrent phase of // marking, everything has been re-initialized and we're // ready to restart.
}
}
}
// These are formatting macros that are used below to ensure // consistent formatting. The *_H_* versions are used to format the // header for a particular value and they should be kept consistent // with the corresponding macro. Also note that most of the macros add // the necessary white space (as a prefix) which makes them a bit // easier to compose.
// All the output lines are prefixed with this string to be able to // identify them easily in a large log file. #define G1PPRL_LINE_PREFIX "###"
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.