8189359: Move native weak oops cleaning out of ReferenceProcessor

Reviewed-by: pliden, kbarrett
This commit is contained in:
Stefan Karlsson 2017-10-18 21:13:35 +02:00
parent 250160bf99
commit 3fbc4aec64
16 changed files with 179 additions and 86 deletions

View File

@ -55,6 +55,7 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
#include "memory/allocation.hpp"
@ -5224,6 +5225,11 @@ void CMSCollector::refProcessingWork() {
pt.print_all_references();
}
{
GCTraceTime(Debug, gc, phases) t("Weak Processing", _gc_timer_cm);
WeakProcessor::weak_oops_do(&_is_alive_closure, &cmsKeepAliveClosure, &cmsDrainMarkingStackClosure);
}
// This is the point where the entire marking should have completed.
verify_work_stacks_empty();

View File

@ -46,6 +46,7 @@
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "gc/shared/workgroup.hpp"
#include "logging/log.hpp"
#include "logging/logStream.hpp"
@ -999,6 +1000,8 @@ void ParNewGeneration::collect(bool full,
_gc_tracer.report_tenuring_threshold(tenuring_threshold());
pt.print_all_references();
WeakProcessor::weak_oops_do(&is_alive, &keep_alive, &evacuate_followers);
if (!promotion_failed()) {
// Swap the survivor spaces.
eden()->clear(SpaceDecorator::Mangle);

View File

@ -70,6 +70,7 @@
#include "gc/shared/preservedMarks.inline.hpp"
#include "gc/shared/referenceProcessor.inline.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
@ -4128,17 +4129,6 @@ public:
}
};
void G1CollectedHeap::process_weak_jni_handles() {
double ref_proc_start = os::elapsedTime();
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
JNIHandles::weak_oops_do(&is_alive, &keep_alive);
double ref_proc_time = os::elapsedTime() - ref_proc_start;
g1_policy()->phase_times()->record_ref_proc_time(ref_proc_time * 1000.0);
}
void G1CollectedHeap::preserve_cm_referents(G1ParScanThreadStateSet* per_thread_states) {
// Any reference objects, in the collection set, that were 'discovered'
// by the CM ref processor should have already been copied (either by
@ -4369,14 +4359,23 @@ void G1CollectedHeap::post_evacuate_collection_set(EvacuationInfo& evacuation_in
process_discovered_references(per_thread_states);
} else {
ref_processor_stw()->verify_no_references_recorded();
process_weak_jni_handles();
}
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
{
double start = os::elapsedTime();
WeakProcessor::weak_oops_do(&is_alive, &keep_alive);
double time_ms = (os::elapsedTime() - start) * 1000.0;
g1_policy()->phase_times()->record_ref_proc_time(time_ms);
}
if (G1StringDedup::is_enabled()) {
double fixup_start = os::elapsedTime();
G1STWIsAliveClosure is_alive(this);
G1KeepAliveClosure keep_alive(this);
G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive, true, g1_policy()->phase_times());
double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0;

View File

@ -303,8 +303,6 @@ private:
void trace_heap(GCWhen::Type when, const GCTracer* tracer);
void process_weak_jni_handles();
// These are macros so that, if the assert fires, we get the correct
// line number, file, etc.

View File

@ -48,6 +48,7 @@
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/taskqueue.inline.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "memory/allocation.hpp"
#include "memory/resourceArea.hpp"
@ -1603,6 +1604,23 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
// Is alive closure.
G1CMIsAliveClosure g1_is_alive(g1h);
// Instances of the 'Keep Alive' and 'Complete GC' closures used
// in serial reference processing. Note these closures are also
// used for serially processing (by the the current thread) the
// JNI references during parallel reference processing.
//
// These closures do not need to synchronize with the worker
// threads involved in parallel reference processing as these
// instances are executed serially by the current thread (e.g.
// reference processing is not multi-threaded and is thus
// performed by the current thread instead of a gang worker).
//
// The gang tasks involved in parallel reference processing create
// their own instances of these closures, which do their own
// synchronization among themselves.
G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
// Inner scope to exclude the cleaning of the string and symbol
// tables from the displayed time.
{
@ -1617,23 +1635,6 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
rp->setup_policy(clear_all_soft_refs);
assert(_global_mark_stack.is_empty(), "mark stack should be empty");
// Instances of the 'Keep Alive' and 'Complete GC' closures used
// in serial reference processing. Note these closures are also
// used for serially processing (by the the current thread) the
// JNI references during parallel reference processing.
//
// These closures do not need to synchronize with the worker
// threads involved in parallel reference processing as these
// instances are executed serially by the current thread (e.g.
// reference processing is not multi-threaded and is thus
// performed by the current thread instead of a gang worker).
//
// The gang tasks involved in parallel reference processing create
// their own instances of these closures, which do their own
// synchronization among themselves.
G1CMKeepAliveAndDrainClosure g1_keep_alive(this, task(0), true /* is_serial */);
G1CMDrainMarkingStackClosure g1_drain_mark_stack(this, task(0), true /* is_serial */);
// We need at least one active thread. If reference processing
// is not multi-threaded we use the current (VMThread) thread,
// otherwise we use the work gang from the G1CollectedHeap and
@ -1687,6 +1688,11 @@ void G1ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
assert(!rp->discovery_enabled(), "Post condition");
}
{
GCTraceTime(Debug, gc, phases) debug("Weak Processing", _gc_timer_cm);
WeakProcessor::weak_oops_do(&g1_is_alive, &g1_keep_alive, &g1_drain_mark_stack);
}
if (has_overflown()) {
// We can not trust g1_is_alive if the marking stack overflowed
return;

View File

@ -43,6 +43,7 @@
#include "gc/shared/modRefBarrierSet.hpp"
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "oops/instanceRefKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
@ -181,6 +182,13 @@ void G1MarkSweep::mark_sweep_phase1(bool& marked_for_unloading,
pt.print_all_references();
}
{
GCTraceTime(Debug, gc, phases) trace("Weak Processing", gc_timer());
WeakProcessor::weak_oops_do(&GenMarkSweep::is_alive,
&GenMarkSweep::keep_alive,
&GenMarkSweep::follow_stack_closure);
}
// This is the point where the entire marking should have completed.
assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed");
@ -272,7 +280,7 @@ void G1MarkSweep::mark_sweep_phase3() {
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
JNIHandles::weak_oops_do(&GenMarkSweep::adjust_pointer_closure);
WeakProcessor::oops_do(&GenMarkSweep::adjust_pointer_closure);
if (G1StringDedup::is_enabled()) {
G1StringDedup::oops_do(&GenMarkSweep::adjust_pointer_closure);

View File

@ -47,6 +47,7 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/biasedLocking.hpp"
@ -542,6 +543,11 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
pt.print_all_references();
}
{
GCTraceTime(Debug, gc, phases) t("Weak Processing", _gc_timer);
WeakProcessor::weak_oops_do(is_alive_closure(), mark_and_push_closure(), follow_stack_closure());
}
// This is the point where the entire marking should have completed.
assert(_marking_stack.is_empty(), "Marking should have completed");
@ -617,7 +623,7 @@ void PSMarkSweep::mark_sweep_phase3() {
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
JNIHandles::weak_oops_do(adjust_pointer_closure());
WeakProcessor::oops_do(adjust_pointer_closure());
CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_from_blobs);

View File

@ -52,6 +52,7 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "memory/resourceArea.hpp"
#include "oops/instanceKlass.inline.hpp"
@ -2118,6 +2119,11 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
pt.print_all_references();
}
{
GCTraceTime(Debug, gc, phases) tm("Weak Processing", &_gc_timer);
WeakProcessor::weak_oops_do(is_alive_closure(), &mark_and_push_closure, &follow_stack_closure);
}
// This is the point where the entire marking should have completed.
assert(cm->marking_stacks_empty(), "Marking should have completed");
@ -2170,8 +2176,7 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
// Now adjust pointers in remaining weak roots. (All of which should
// have been cleared if they pointed to non-surviving objects.)
// Global (weak) JNI handles
JNIHandles::weak_oops_do(&oop_closure);
WeakProcessor::oops_do(&oop_closure);
CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations);
CodeCache::blobs_do(&adjust_from_blobs);

View File

@ -45,6 +45,7 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/referenceProcessor.hpp"
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "memory/resourceArea.hpp"
#include "logging/log.hpp"
#include "oops/oop.inline.hpp"
@ -406,14 +407,15 @@ bool PSScavenge::invoke_no_policy() {
scavenge_midpoint.update();
PSKeepAliveClosure keep_alive(promotion_manager);
PSEvacuateFollowersClosure evac_followers(promotion_manager);
// Process reference objects discovered during scavenge
{
GCTraceTime(Debug, gc, phases) tm("Reference Processing", &_gc_timer);
reference_processor()->setup_policy(false); // not always_clear
reference_processor()->set_active_mt_degree(active_workers);
PSKeepAliveClosure keep_alive(promotion_manager);
PSEvacuateFollowersClosure evac_followers(promotion_manager);
ReferenceProcessorStats stats;
ReferenceProcessorPhaseTimes pt(&_gc_timer, reference_processor()->num_q());
if (reference_processor()->processing_is_mt()) {
@ -440,6 +442,11 @@ bool PSScavenge::invoke_no_policy() {
pt.print_enqueue_phase();
}
{
GCTraceTime(Debug, gc, phases) tm("Weak Processing", &_gc_timer);
WeakProcessor::weak_oops_do(&_is_alive_closure, &keep_alive, &evac_followers);
}
{
GCTraceTime(Debug, gc, phases) tm("Scrub String Table", &_gc_timer);
// Unlink any dead interned Strings and process the remaining live ones.

View File

@ -41,6 +41,7 @@
#include "gc/shared/space.inline.hpp"
#include "gc/shared/spaceDecorator.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "logging/log.hpp"
#include "memory/iterator.hpp"
#include "memory/resourceArea.hpp"
@ -658,6 +659,8 @@ void DefNewGeneration::collect(bool full,
gc_tracer.report_tenuring_threshold(tenuring_threshold());
pt.print_all_references();
WeakProcessor::weak_oops_do(&is_alive, &keep_alive, &evacuate_followers);
if (!_promotion_failed) {
// Swap the survivor spaces.
eden()->clear(SpaceDecorator::Mangle);

View File

@ -43,6 +43,7 @@
#include "gc/shared/referencePolicy.hpp"
#include "gc/shared/space.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "oops/instanceRefKlass.hpp"
#include "oops/oop.inline.hpp"
#include "prims/jvmtiExport.hpp"
@ -217,6 +218,11 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
gc_tracer()->report_gc_reference_stats(stats);
}
{
GCTraceTime(Debug, gc, phases) tm_m("Weak Processing", gc_timer());
WeakProcessor::weak_oops_do(&is_alive, &keep_alive, &follow_stack_closure);
}
// This is the point where the entire marking should have completed.
assert(_marking_stack.is_empty(), "Marking should have completed");

View File

@ -42,6 +42,7 @@
#include "gc/shared/space.hpp"
#include "gc/shared/strongRootsScope.hpp"
#include "gc/shared/vmGCOperations.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "gc/shared/workgroup.hpp"
#include "memory/filemap.hpp"
#include "memory/resourceArea.hpp"
@ -652,7 +653,7 @@ void GenCollectedHeap::full_process_roots(StrongRootsScope* scope,
}
void GenCollectedHeap::gen_process_weak_roots(OopClosure* root_closure) {
JNIHandles::weak_oops_do(root_closure);
WeakProcessor::oops_do(root_closure);
_young_gen->ref_processor()->weak_oops_do(root_closure);
_old_gen->ref_processor()->weak_oops_do(root_closure);
}

View File

@ -36,7 +36,6 @@
#include "memory/resourceArea.hpp"
#include "oops/oop.inline.hpp"
#include "runtime/java.hpp"
#include "runtime/jniHandles.hpp"
ReferencePolicy* ReferenceProcessor::_always_clear_soft_ref_policy = NULL;
ReferencePolicy* ReferenceProcessor::_default_soft_ref_policy = NULL;
@ -245,51 +244,16 @@ ReferenceProcessorStats ReferenceProcessor::process_discovered_references(
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);
if (task_executor != NULL) {
// Record the work done by the parallel workers.
task_executor->set_single_threaded_mode();
}
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;
}
#ifndef PRODUCT
// Calculate the number of jni handles.
size_t ReferenceProcessor::count_jni_refs() {
class CountHandleClosure: public OopClosure {
private:
size_t _count;
public:
CountHandleClosure(): _count(0) {}
void do_oop(oop* unused) { _count++; }
void do_oop(narrowOop* unused) { ShouldNotReachHere(); }
size_t count() { return _count; }
};
CountHandleClosure global_handle_count;
JNIHandles::weak_oops_do(&global_handle_count);
return global_handle_count.count();
}
#endif
void ReferenceProcessor::process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
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

View File

@ -246,10 +246,6 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
AbstractRefProcTaskExecutor* task_executor,
ReferenceProcessorPhaseTimes* phase_times);
void process_phaseJNI(BoolObjectClosure* is_alive,
OopClosure* keep_alive,
VoidClosure* complete_gc);
// Work methods used by the method process_discovered_reflist
// Phase1: keep alive all those referents that are otherwise
// dead but which must be kept alive by policy (and their closure).
@ -341,9 +337,6 @@ class ReferenceProcessor : public CHeapObj<mtGC> {
void clear_discovered_references(DiscoveredList& refs_list);
// Calculate the number of jni handles.
size_t count_jni_refs();
void log_reflist_counts(DiscoveredList ref_lists[], uint active_length, size_t total_count) PRODUCT_RETURN;
// Balances reference queues.

View File

@ -0,0 +1,39 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#include "precompiled.hpp"
#include "gc/shared/weakProcessor.hpp"
#include "runtime/jniHandles.hpp"
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete) {
JNIHandles::weak_oops_do(is_alive, keep_alive);
if (complete != NULL) {
complete->do_void();
}
}
void WeakProcessor::oops_do(OopClosure* closure) {
AlwaysTrueClosure always_true;
JNIHandles::weak_oops_do(&always_true, closure);
}

View File

@ -0,0 +1,49 @@
/*
* Copyright (c) 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.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*
*/
#ifndef SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP
#define SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP
#include "memory/allocation.hpp"
#include "memory/iterator.hpp"
// Helper class to aid in root scanning and cleaning of weak oops in the VM.
//
// New containers of weak oops added to this class will automatically
// be cleaned by all GCs, including the young generation GCs.
class WeakProcessor : AllStatic {
public:
// Visit all oop*s and apply the keep_alive closure if the referenced
// object is considered alive by the is_alive closure, otherwise do some
// container specific cleanup of element holding the oop.
//
// The complete closure is used as a post-processing step,
// called after all container have been processed.
static void weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive, VoidClosure* complete = NULL);
// Visit all oop*s and apply the given closure.
static void oops_do(OopClosure* closure);
};
#endif // SHARE_VM_GC_SHARED_WEAKPROCESSOR_HPP