< prev index next >
src/share/vm/gc/shared/referenceProcessor.cpp
Print this page
rev 13328 : [mq]: webrev.0b
rev 13330 : imported patch webrev.2
rev 13331 : imported patch webrev.3b
*** 1,7 ****
/*
! * Copyright (c) 2001, 2016, 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.
--- 1,7 ----
/*
! * Copyright (c) 2001, 2017, 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.
*** 177,187 ****
}
// Else leave clock stalled at its old value until time progresses
// past clock value.
}
! size_t ReferenceProcessor::total_count(DiscoveredList lists[]) {
size_t total = 0;
for (uint i = 0; i < _max_num_q; ++i) {
total += lists[i].length();
}
return total;
--- 177,187 ----
}
// Else leave clock stalled at its old value until time progresses
// past clock value.
}
! size_t ReferenceProcessor::total_count(DiscoveredList lists[]) const {
size_t total = 0;
for (uint i = 0; i < _max_num_q; ++i) {
total += lists[i].length();
}
return total;
*** 190,200 ****
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor,
! GCTimer* gc_timer) {
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
// Stop treating discovered references specially.
disable_discovery();
--- 190,201 ----
ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
AbstractRefProcTaskExecutor* task_executor,
! ReferenceProcessorPhaseTimes* phase_times) {
! double start_time = os::elapsedTime();
assert(!enqueuing_is_done(), "If here enqueuing should not be complete");
// Stop treating discovered references specially.
disable_discovery();
*** 206,266 ****
// here so that we use the new value during processing of the
// discovered soft refs.
_soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
! ReferenceProcessorStats stats(
! total_count(_discoveredSoftRefs),
total_count(_discoveredWeakRefs),
total_count(_discoveredFinalRefs),
total_count(_discoveredPhantomRefs));
// Soft references
{
! GCTraceTime(Debug, gc, ref) tt("SoftReference", gc_timer);
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
! is_alive, keep_alive, complete_gc, task_executor);
}
update_soft_ref_master_clock();
// Weak references
{
! GCTraceTime(Debug, gc, ref) tt("WeakReference", gc_timer);
process_discovered_reflist(_discoveredWeakRefs, NULL, true,
! is_alive, keep_alive, complete_gc, task_executor);
}
// Final references
{
! GCTraceTime(Debug, gc, ref) tt("FinalReference", gc_timer);
process_discovered_reflist(_discoveredFinalRefs, NULL, false,
! is_alive, keep_alive, complete_gc, task_executor);
}
// Phantom references
{
! GCTraceTime(Debug, gc, ref) tt("PhantomReference", gc_timer);
process_discovered_reflist(_discoveredPhantomRefs, NULL, true,
! is_alive, keep_alive, complete_gc, task_executor);
}
// Weak global JNI references. It would make more sense (semantically) to
// traverse these simultaneously with the regular weak references above, but
// that is not how the JDK1.2 specification is. See #4126360. Native code can
// thus use JNI weak references to circumvent the phantom references and
// resurrect a "post-mortem" object.
{
! GCTraceTime(Debug, gc, ref) tt("JNI Weak Reference", gc_timer);
if (task_executor != NULL) {
task_executor->set_single_threaded_mode();
}
process_phaseJNI(is_alive, keep_alive, complete_gc);
}
! log_debug(gc, ref)("Ref Counts: Soft: " SIZE_FORMAT " Weak: " SIZE_FORMAT " Final: " SIZE_FORMAT " Phantom: " SIZE_FORMAT,
! stats.soft_count(), stats.weak_count(), stats.final_count(), stats.phantom_count());
log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs());
return stats;
}
--- 207,266 ----
// here so that we use the new value during processing of the
// discovered soft refs.
_soft_ref_timestamp_clock = java_lang_ref_SoftReference::clock();
! ReferenceProcessorStats stats(total_count(_discoveredSoftRefs),
total_count(_discoveredWeakRefs),
total_count(_discoveredFinalRefs),
total_count(_discoveredPhantomRefs));
// Soft references
{
! RefProcPhaseTimesTracker tt(REF_SOFT, phase_times, this);
process_discovered_reflist(_discoveredSoftRefs, _current_soft_ref_policy, true,
! is_alive, keep_alive, complete_gc, task_executor, phase_times);
}
update_soft_ref_master_clock();
// Weak references
{
! RefProcPhaseTimesTracker tt(REF_WEAK, phase_times, this);
process_discovered_reflist(_discoveredWeakRefs, NULL, true,
! is_alive, keep_alive, complete_gc, task_executor, phase_times);
}
// Final references
{
! RefProcPhaseTimesTracker tt(REF_FINAL, phase_times, this);
process_discovered_reflist(_discoveredFinalRefs, NULL, false,
! is_alive, keep_alive, complete_gc, task_executor, phase_times);
}
// Phantom references
{
! RefProcPhaseTimesTracker tt(REF_PHANTOM, phase_times, this);
process_discovered_reflist(_discoveredPhantomRefs, NULL, true,
! is_alive, keep_alive, complete_gc, task_executor, phase_times);
}
// Weak global JNI references. It would make more sense (semantically) to
// traverse these simultaneously with the regular weak references above, but
// that is not how the JDK1.2 specification is. See #4126360. Native code can
// thus use JNI weak references to circumvent the phantom references and
// resurrect a "post-mortem" object.
{
! GCTraceTime(Debug, gc, ref) tt("JNI Weak Reference", phase_times->gc_timer());
if (task_executor != NULL) {
task_executor->set_single_threaded_mode();
}
process_phaseJNI(is_alive, keep_alive, complete_gc);
}
! phase_times->set_total_time_ms((os::elapsedTime() - start_time) * 1000);
!
log_develop_trace(gc, ref)("JNI Weak Reference count: " SIZE_FORMAT, count_jni_refs());
return stats;
}
*** 287,300 ****
VoidClosure* complete_gc) {
JNIHandles::weak_oops_do(is_alive, keep_alive);
complete_gc->do_void();
}
! void ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor) {
// Enqueue references that are not made active again, and
// clear the decks for the next collection (cycle).
! enqueue_discovered_reflists(task_executor);
// Stop treating discovered references specially.
disable_discovery();
}
--- 287,301 ----
VoidClosure* complete_gc) {
JNIHandles::weak_oops_do(is_alive, keep_alive);
complete_gc->do_void();
}
! void ReferenceProcessor::enqueue_discovered_references(AbstractRefProcTaskExecutor* task_executor,
! ReferenceProcessorPhaseTimes* phase_times) {
// Enqueue references that are not made active again, and
// clear the decks for the next collection (cycle).
! enqueue_discovered_reflists(task_executor, phase_times);
// Stop treating discovered references specially.
disable_discovery();
}
*** 343,357 ****
// Parallel enqueue task
class RefProcEnqueueTask: public AbstractRefProcTaskExecutor::EnqueueTask {
public:
RefProcEnqueueTask(ReferenceProcessor& ref_processor,
DiscoveredList discovered_refs[],
! int n_queues)
! : EnqueueTask(ref_processor, discovered_refs, n_queues)
{ }
virtual void work(unsigned int work_id) {
assert(work_id < (unsigned int)_ref_processor.max_num_q(), "Index out-of-bounds");
// Simplest first cut: static partitioning.
int index = work_id;
// The increment on "index" must correspond to the maximum number of queues
// (n_queues) with which that ReferenceProcessor was created. That
--- 344,361 ----
// Parallel enqueue task
class RefProcEnqueueTask: public AbstractRefProcTaskExecutor::EnqueueTask {
public:
RefProcEnqueueTask(ReferenceProcessor& ref_processor,
DiscoveredList discovered_refs[],
! int n_queues,
! ReferenceProcessorPhaseTimes* phase_times)
! : EnqueueTask(ref_processor, discovered_refs, n_queues, phase_times)
{ }
virtual void work(unsigned int work_id) {
+ RefProcWorkerTimeTracker tt(ReferenceProcessorPhaseTimes::RefEnqueue, _phase_times, work_id);
+
assert(work_id < (unsigned int)_ref_processor.max_num_q(), "Index out-of-bounds");
// Simplest first cut: static partitioning.
int index = work_id;
// The increment on "index" must correspond to the maximum number of queues
// (n_queues) with which that ReferenceProcessor was created. That
*** 367,380 ****
}
}
};
// Enqueue references that are not made active again
! void ReferenceProcessor::enqueue_discovered_reflists(AbstractRefProcTaskExecutor* task_executor) {
if (_processing_is_mt && task_executor != NULL) {
// Parallel code
! RefProcEnqueueTask tsk(*this, _discovered_refs, _max_num_q);
task_executor->execute(tsk);
} else {
// Serial code: call the parent class's implementation
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
enqueue_discovered_reflist(_discovered_refs[i]);
--- 371,393 ----
}
}
};
// Enqueue references that are not made active again
! void ReferenceProcessor::enqueue_discovered_reflists(AbstractRefProcTaskExecutor* task_executor,
! ReferenceProcessorPhaseTimes* phase_times) {
!
! ReferenceProcessorStats stats(total_count(_discoveredSoftRefs),
! total_count(_discoveredWeakRefs),
! total_count(_discoveredFinalRefs),
! total_count(_discoveredPhantomRefs));
!
! RefProcEnqueueTimeTracker tt(phase_times, stats);
!
if (_processing_is_mt && task_executor != NULL) {
// Parallel code
! RefProcEnqueueTask tsk(*this, _discovered_refs, _max_num_q, phase_times);
task_executor->execute(tsk);
} else {
// Serial code: call the parent class's implementation
for (uint i = 0; i < _max_num_q * number_of_subclasses_of_ref(); i++) {
enqueue_discovered_reflist(_discovered_refs[i]);
*** 467,477 ****
}
// Close the reachable set
complete_gc->do_void();
log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " dead Refs out of " SIZE_FORMAT " discovered Refs by policy, from list " INTPTR_FORMAT,
iter.removed(), iter.processed(), p2i(&refs_list));
! }
// Traverse the list and remove any Refs that are not active, or
// whose referents are either alive or NULL.
void
ReferenceProcessor::pp2_work(DiscoveredList& refs_list,
--- 480,490 ----
}
// Close the reachable set
complete_gc->do_void();
log_develop_trace(gc, ref)(" Dropped " SIZE_FORMAT " dead Refs out of " SIZE_FORMAT " discovered Refs by policy, from list " INTPTR_FORMAT,
iter.removed(), iter.processed(), p2i(&refs_list));
! }
// Traverse the list and remove any Refs that are not active, or
// whose referents are either alive or NULL.
void
ReferenceProcessor::pp2_work(DiscoveredList& refs_list,
*** 596,618 ****
}
clear_discovered_references(_discovered_refs[i]);
}
}
class RefProcPhase1Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase1Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
ReferencePolicy* policy,
! bool marks_oops_alive)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive),
_policy(policy)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
_ref_processor.process_phase1(_refs_lists[i], _policy,
&is_alive, &keep_alive, &complete_gc);
}
private:
ReferencePolicy* _policy;
--- 609,658 ----
}
clear_discovered_references(_discovered_refs[i]);
}
}
+ size_t ReferenceProcessor::total_reference_count(ReferenceType type) const {
+ DiscoveredList* list = NULL;
+
+ switch (type) {
+ case REF_SOFT:
+ list = _discoveredSoftRefs;
+ break;
+ case REF_WEAK:
+ list = _discoveredWeakRefs;
+ break;
+ case REF_FINAL:
+ list = _discoveredFinalRefs;
+ break;
+ case REF_PHANTOM:
+ list = _discoveredPhantomRefs;
+ break;
+ case REF_OTHER:
+ case REF_NONE:
+ default:
+ ShouldNotReachHere();
+ }
+ return total_count(list);
+ }
+
class RefProcPhase1Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase1Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
ReferencePolicy* policy,
! bool marks_oops_alive,
! ReferenceProcessorPhaseTimes* phase_times)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive, phase_times),
_policy(policy)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
+ RefProcWorkerTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase1, _phase_times, i);
+
_ref_processor.process_phase1(_refs_lists[i], _policy,
&is_alive, &keep_alive, &complete_gc);
}
private:
ReferencePolicy* _policy;
*** 620,654 ****
class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase2Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
! bool marks_oops_alive)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
_ref_processor.process_phase2(_refs_lists[i],
&is_alive, &keep_alive, &complete_gc);
}
};
class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase3Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
bool clear_referent,
! bool marks_oops_alive)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive),
_clear_referent(clear_referent)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
_ref_processor.process_phase3(_refs_lists[i], _clear_referent,
&is_alive, &keep_alive, &complete_gc);
}
private:
bool _clear_referent;
--- 660,700 ----
class RefProcPhase2Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase2Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
! bool marks_oops_alive,
! ReferenceProcessorPhaseTimes* phase_times)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive, phase_times)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
+ RefProcWorkerTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase2, _phase_times, i);
+
_ref_processor.process_phase2(_refs_lists[i],
&is_alive, &keep_alive, &complete_gc);
}
};
class RefProcPhase3Task: public AbstractRefProcTaskExecutor::ProcessTask {
public:
RefProcPhase3Task(ReferenceProcessor& ref_processor,
DiscoveredList refs_lists[],
bool clear_referent,
! bool marks_oops_alive,
! ReferenceProcessorPhaseTimes* phase_times)
! : ProcessTask(ref_processor, refs_lists, marks_oops_alive, phase_times),
_clear_referent(clear_referent)
{ }
virtual void work(unsigned int i, BoolObjectClosure& is_alive,
OopClosure& keep_alive,
VoidClosure& complete_gc)
{
+ RefProcWorkerTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase3, _phase_times, i);
+
_ref_processor.process_phase3(_refs_lists[i], _clear_referent,
&is_alive, &keep_alive, &complete_gc);
}
private:
bool _clear_referent;
*** 774,807 ****
ReferencePolicy* policy,
bool clear_referent,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
! AbstractRefProcTaskExecutor* task_executor)
{
bool mt_processing = task_executor != NULL && _processing_is_mt;
// If discovery used MT and a dynamic number of GC threads, then
// the queues must be balanced for correctness if fewer than the
// maximum number of queues were used. The number of queue used
// during discovery may be different than the number to be used
// for processing so don't depend of _num_q < _max_num_q as part
// of the test.
bool must_balance = _discovery_is_mt;
if ((mt_processing && ParallelRefProcBalancingEnabled) ||
must_balance) {
balance_queues(refs_lists);
}
// Phase 1 (soft refs only):
// . Traverse the list and remove any SoftReferences whose
// referents are not alive, but that should be kept alive for
// policy reasons. Keep alive the transitive closure of all
// such referents.
if (policy != NULL) {
if (mt_processing) {
! RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/);
task_executor->execute(phase1);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase1(refs_lists[i], policy,
is_alive, keep_alive, complete_gc);
--- 820,860 ----
ReferencePolicy* policy,
bool clear_referent,
BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc,
! AbstractRefProcTaskExecutor* task_executor,
! ReferenceProcessorPhaseTimes* phase_times)
{
bool mt_processing = task_executor != NULL && _processing_is_mt;
+
+ phase_times->set_processing_is_mt(mt_processing);
+
// If discovery used MT and a dynamic number of GC threads, then
// the queues must be balanced for correctness if fewer than the
// maximum number of queues were used. The number of queue used
// during discovery may be different than the number to be used
// for processing so don't depend of _num_q < _max_num_q as part
// of the test.
bool must_balance = _discovery_is_mt;
if ((mt_processing && ParallelRefProcBalancingEnabled) ||
must_balance) {
+ RefProcBalanceQueuesTimeTracker tt(phase_times);
balance_queues(refs_lists);
}
// Phase 1 (soft refs only):
// . Traverse the list and remove any SoftReferences whose
// referents are not alive, but that should be kept alive for
// policy reasons. Keep alive the transitive closure of all
// such referents.
if (policy != NULL) {
+ RefProcParPhaseTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase1, phase_times);
+
if (mt_processing) {
! RefProcPhase1Task phase1(*this, refs_lists, policy, true /*marks_oops_alive*/, phase_times);
task_executor->execute(phase1);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase1(refs_lists[i], policy,
is_alive, keep_alive, complete_gc);
*** 812,841 ****
"Policy must be specified for soft references.");
}
// Phase 2:
// . Traverse the list and remove any refs whose referents are alive.
if (mt_processing) {
! RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/);
task_executor->execute(phase2);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);
}
}
// Phase 3:
// . Traverse the list and process referents as appropriate.
if (mt_processing) {
! RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/);
task_executor->execute(phase3);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase3(refs_lists[i], clear_referent,
is_alive, keep_alive, complete_gc);
}
}
}
inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
uint id = 0;
// Determine the queue index to use for this object.
--- 865,902 ----
"Policy must be specified for soft references.");
}
// Phase 2:
// . Traverse the list and remove any refs whose referents are alive.
+ {
+ RefProcParPhaseTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase2, phase_times);
+
if (mt_processing) {
! RefProcPhase2Task phase2(*this, refs_lists, !discovery_is_atomic() /*marks_oops_alive*/, phase_times);
task_executor->execute(phase2);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase2(refs_lists[i], is_alive, keep_alive, complete_gc);
}
}
+ }
// Phase 3:
// . Traverse the list and process referents as appropriate.
+ {
+ RefProcParPhaseTimeTracker tt(ReferenceProcessorPhaseTimes::RefPhase3, phase_times);
+
if (mt_processing) {
! RefProcPhase3Task phase3(*this, refs_lists, clear_referent, true /*marks_oops_alive*/, phase_times);
task_executor->execute(phase3);
} else {
for (uint i = 0; i < _max_num_q; i++) {
process_phase3(refs_lists[i], clear_referent,
is_alive, keep_alive, complete_gc);
}
}
+ }
}
inline DiscoveredList* ReferenceProcessor::get_discovered_list(ReferenceType rt) {
uint id = 0;
// Determine the queue index to use for this object.
*** 1194,1199 ****
case 3: return "PhantomRef";
}
ShouldNotReachHere();
return NULL;
}
-
--- 1255,1259 ----
< prev index next >