8213229: Investigate treating StringTable as weak in young collections
Reviewed-by: zgu, kbarrett
This commit is contained in:
parent
51e2252a73
commit
d800361151
src/hotspot/share
classfile
gc
cms
g1
g1CollectedHeap.cppg1CollectedHeap.hppg1ConcurrentMark.cppg1FullCollector.cppg1FullGCAdjustTask.cppg1FullGCAdjustTask.hppg1FullGCMarkTask.cppg1GCPhaseTimes.cppg1GCPhaseTimes.hppg1HeapVerifier.cppg1RootProcessor.cppg1RootProcessor.hppg1StringDedup.cppg1StringDedup.hpp
parallel
serial
shared
genCollectedHeap.cppgenCollectedHeap.hppparallelCleaning.cppparallelCleaning.hpp
stringdedup
weakProcessor.cppweakProcessor.inline.hppweakProcessorPhaseTimes.cppweakProcessorPhaseTimes.hppweakProcessorPhases.cppweakProcessorPhases.hppshenandoah
logging
test
hotspot/jtreg/gc/g1
jdk/jdk/jfr/event/gc/collection
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 1997, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 1997, 2019, 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
|
||||
@ -376,68 +376,11 @@ oop StringTable::do_intern(Handle string_or_null_h, const jchar* name,
|
||||
} while(true);
|
||||
}
|
||||
|
||||
// GC support
|
||||
class StringTableIsAliveCounter : public BoolObjectClosure {
|
||||
BoolObjectClosure* _real_boc;
|
||||
public:
|
||||
size_t _count;
|
||||
size_t _count_total;
|
||||
StringTableIsAliveCounter(BoolObjectClosure* boc) : _real_boc(boc), _count(0),
|
||||
_count_total(0) {}
|
||||
bool do_object_b(oop obj) {
|
||||
bool ret = _real_boc->do_object_b(obj);
|
||||
if (!ret) {
|
||||
++_count;
|
||||
}
|
||||
++_count_total;
|
||||
return ret;
|
||||
}
|
||||
};
|
||||
|
||||
void StringTable::unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f,
|
||||
size_t* processed, size_t* removed) {
|
||||
DoNothingClosure dnc;
|
||||
assert(is_alive != NULL, "No closure");
|
||||
StringTableIsAliveCounter stiac(is_alive);
|
||||
OopClosure* tmp = f != NULL ? f : &dnc;
|
||||
|
||||
StringTable::the_table()->_weak_handles->weak_oops_do(&stiac, tmp);
|
||||
|
||||
// This is the serial case without ParState.
|
||||
// Just set the correct number and check for a cleaning phase.
|
||||
the_table()->_uncleaned_items_count = stiac._count;
|
||||
StringTable::the_table()->check_concurrent_work();
|
||||
|
||||
if (processed != NULL) {
|
||||
*processed = stiac._count_total;
|
||||
}
|
||||
if (removed != NULL) {
|
||||
*removed = stiac._count;
|
||||
}
|
||||
}
|
||||
|
||||
void StringTable::oops_do(OopClosure* f) {
|
||||
assert(f != NULL, "No closure");
|
||||
StringTable::the_table()->_weak_handles->oops_do(f);
|
||||
}
|
||||
|
||||
void StringTable::possibly_parallel_unlink(
|
||||
OopStorage::ParState<false, false>* _par_state_string, BoolObjectClosure* cl,
|
||||
size_t* processed, size_t* removed)
|
||||
{
|
||||
DoNothingClosure dnc;
|
||||
assert(cl != NULL, "No closure");
|
||||
StringTableIsAliveCounter stiac(cl);
|
||||
|
||||
_par_state_string->weak_oops_do(&stiac, &dnc);
|
||||
|
||||
// Accumulate the dead strings.
|
||||
the_table()->add_items_to_clean(stiac._count);
|
||||
|
||||
*processed = stiac._count_total;
|
||||
*removed = stiac._count;
|
||||
}
|
||||
|
||||
void StringTable::possibly_parallel_oops_do(
|
||||
OopStorage::ParState<false /* concurrent */, false /* const */>*
|
||||
_par_state_string, OopClosure* f)
|
||||
|
@ -128,20 +128,10 @@ private:
|
||||
the_table()->add_items_to_clean(ndead);
|
||||
}
|
||||
|
||||
// Delete pointers to otherwise-unreachable objects.
|
||||
static void unlink(BoolObjectClosure* cl) {
|
||||
unlink_or_oops_do(cl);
|
||||
}
|
||||
static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* f = NULL,
|
||||
size_t* processed = NULL, size_t* removed = NULL);
|
||||
|
||||
// Serially invoke "f->do_oop" on the locations of all oops in the table.
|
||||
static void oops_do(OopClosure* f);
|
||||
|
||||
// Possibly parallel versions of the above
|
||||
static void possibly_parallel_unlink(
|
||||
OopStorage::ParState<false /* concurrent */, false /* const*/>* par_state_string,
|
||||
BoolObjectClosure* cl, size_t* processed, size_t* removed);
|
||||
static void possibly_parallel_oops_do(
|
||||
OopStorage::ParState<false /* concurrent */, false /* const*/>* par_state_string,
|
||||
OopClosure* f);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -225,15 +225,11 @@ void CMSHeap::cms_process_roots(StrongRootsScope* scope,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string) {
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, !CodeBlobToOopClosure::FixRelocations);
|
||||
CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
|
||||
|
||||
process_roots(scope, so, root_closure, cld_closure, weak_cld_closure, &mark_code_closure);
|
||||
if (!only_strong_roots) {
|
||||
process_string_table_roots(scope, root_closure, par_state_string);
|
||||
}
|
||||
|
||||
if (young_gen_as_roots &&
|
||||
_process_strong_tasks->try_claim_task(GCH_PS_younger_gens)) {
|
||||
|
@ -91,8 +91,7 @@ public:
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string = NULL);
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
GCMemoryManager* old_manager() const { return _old_manager; }
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -4333,8 +4333,7 @@ void CMSParInitialMarkTask::work(uint worker_id) {
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mri_cl,
|
||||
&cld_closure,
|
||||
&_par_state_string);
|
||||
&cld_closure);
|
||||
|
||||
assert(_collector->should_unload_classes()
|
||||
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
@ -4464,8 +4463,7 @@ void CMSParRemarkTask::work(uint worker_id) {
|
||||
GenCollectedHeap::ScanningOption(_collector->CMSCollector::roots_scanning_options()),
|
||||
_collector->should_unload_classes(),
|
||||
&par_mrias_cl,
|
||||
NULL, // The dirty klasses will be handled below
|
||||
&_par_state_string);
|
||||
NULL); // The dirty klasses will be handled below
|
||||
|
||||
assert(_collector->should_unload_classes()
|
||||
|| (_collector->CMSCollector::roots_scanning_options() & GenCollectedHeap::SO_AllCodeCache),
|
||||
@ -5277,12 +5275,6 @@ void CMSCollector::refProcessingWork() {
|
||||
// Clean up unreferenced symbols in symbol table.
|
||||
SymbolTable::unlink();
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer_cm);
|
||||
// Delete entries for dead interned strings.
|
||||
StringTable::unlink(&_is_alive_closure);
|
||||
}
|
||||
}
|
||||
|
||||
// Restore any preserved marks as a result of mark stack or
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -606,8 +606,7 @@ void ParNewGenTask::work(uint worker_id) {
|
||||
heap->young_process_roots(_strong_roots_scope,
|
||||
&par_scan_state.to_space_root_closure(),
|
||||
&par_scan_state.older_gen_closure(),
|
||||
&cld_scan_closure,
|
||||
&_par_state_string);
|
||||
&cld_scan_closure);
|
||||
|
||||
par_scan_state.end_strong_roots();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -3362,24 +3362,54 @@ void G1CollectedHeap::print_termination_stats(uint worker_id,
|
||||
|
||||
void G1CollectedHeap::complete_cleaning(BoolObjectClosure* is_alive,
|
||||
bool class_unloading_occurred) {
|
||||
uint n_workers = workers()->active_workers();
|
||||
|
||||
G1StringDedupUnlinkOrOopsDoClosure dedup_closure(is_alive, NULL, false);
|
||||
ParallelCleaningTask g1_unlink_task(is_alive, &dedup_closure, n_workers, class_unloading_occurred);
|
||||
workers()->run_task(&g1_unlink_task);
|
||||
uint num_workers = workers()->active_workers();
|
||||
ParallelCleaningTask unlink_task(is_alive, num_workers, class_unloading_occurred, false);
|
||||
workers()->run_task(&unlink_task);
|
||||
}
|
||||
|
||||
void G1CollectedHeap::partial_cleaning(BoolObjectClosure* is_alive,
|
||||
bool process_strings,
|
||||
bool process_string_dedup) {
|
||||
if (!process_strings && !process_string_dedup) {
|
||||
// Nothing to clean.
|
||||
return;
|
||||
// Clean string dedup data structures.
|
||||
// Ideally we would prefer to use a StringDedupCleaningTask here, but we want to
|
||||
// record the durations of the phases. Hence the almost-copy.
|
||||
class G1StringDedupCleaningTask : public AbstractGangTask {
|
||||
BoolObjectClosure* _is_alive;
|
||||
OopClosure* _keep_alive;
|
||||
G1GCPhaseTimes* _phase_times;
|
||||
|
||||
public:
|
||||
G1StringDedupCleaningTask(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
G1GCPhaseTimes* phase_times) :
|
||||
AbstractGangTask("Partial Cleaning Task"),
|
||||
_is_alive(is_alive),
|
||||
_keep_alive(keep_alive),
|
||||
_phase_times(phase_times)
|
||||
{
|
||||
assert(G1StringDedup::is_enabled(), "String deduplication disabled.");
|
||||
StringDedup::gc_prologue(true);
|
||||
}
|
||||
|
||||
G1StringDedupUnlinkOrOopsDoClosure dedup_closure(is_alive, NULL, false);
|
||||
StringCleaningTask g1_unlink_task(is_alive, process_string_dedup ? &dedup_closure : NULL, process_strings);
|
||||
workers()->run_task(&g1_unlink_task);
|
||||
~G1StringDedupCleaningTask() {
|
||||
StringDedup::gc_epilogue();
|
||||
}
|
||||
|
||||
void work(uint worker_id) {
|
||||
StringDedupUnlinkOrOopsDoClosure cl(_is_alive, _keep_alive);
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupQueueFixup, worker_id);
|
||||
StringDedupQueue::unlink_or_oops_do(&cl);
|
||||
}
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupTableFixup, worker_id);
|
||||
StringDedupTable::unlink_or_oops_do(&cl, worker_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void G1CollectedHeap::string_dedup_cleaning(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
G1GCPhaseTimes* phase_times) {
|
||||
G1StringDedupCleaningTask cl(is_alive, keep_alive, phase_times);
|
||||
workers()->run_task(&cl);
|
||||
}
|
||||
|
||||
class G1RedirtyLoggedCardsTask : public AbstractGangTask {
|
||||
@ -3911,11 +3941,6 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_
|
||||
// not copied during the pause.
|
||||
process_discovered_references(per_thread_states);
|
||||
|
||||
// FIXME
|
||||
// CM's reference processing also cleans up the string table.
|
||||
// Should we do that here also? We could, but it is a serial operation
|
||||
// and could significantly increase the pause time.
|
||||
|
||||
G1STWIsAliveClosure is_alive(this);
|
||||
G1KeepAliveClosure keep_alive(this);
|
||||
|
||||
@ -3923,12 +3948,12 @@ void G1CollectedHeap::post_evacuate_collection_set(G1EvacuationInfo& evacuation_
|
||||
g1_policy()->phase_times()->weak_phase_times());
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
double fixup_start = os::elapsedTime();
|
||||
double string_dedup_time_ms = os::elapsedTime();
|
||||
|
||||
G1StringDedup::unlink_or_oops_do(&is_alive, &keep_alive, true, g1_policy()->phase_times());
|
||||
string_dedup_cleaning(&is_alive, &keep_alive, g1_policy()->phase_times());
|
||||
|
||||
double fixup_time_ms = (os::elapsedTime() - fixup_start) * 1000.0;
|
||||
g1_policy()->phase_times()->record_string_dedup_fixup_time(fixup_time_ms);
|
||||
double string_cleanup_time_ms = (os::elapsedTime() - string_dedup_time_ms) * 1000.0;
|
||||
g1_policy()->phase_times()->record_string_deduplication_time(string_cleanup_time_ms);
|
||||
}
|
||||
|
||||
if (evacuation_failed()) {
|
||||
|
@ -1332,14 +1332,12 @@ public:
|
||||
// after a full GC.
|
||||
void rebuild_strong_code_roots();
|
||||
|
||||
// Partial cleaning used when class unloading is disabled.
|
||||
// Let the caller choose what structures to clean out:
|
||||
// - StringTable
|
||||
// - StringDeduplication structures
|
||||
void partial_cleaning(BoolObjectClosure* is_alive, bool unlink_strings, bool unlink_string_dedup);
|
||||
// Partial cleaning of VM internal data structures.
|
||||
void string_dedup_cleaning(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
G1GCPhaseTimes* phase_times = NULL);
|
||||
|
||||
// Complete cleaning used when class unloading is enabled.
|
||||
// Cleans out all structures handled by partial_cleaning and also the CodeCache.
|
||||
// Performs cleaning of data structures after class unloading.
|
||||
void complete_cleaning(BoolObjectClosure* is_alive, bool class_unloading_occurred);
|
||||
|
||||
// Redirty logged cards in the refinement queue.
|
||||
|
@ -1655,11 +1655,9 @@ void G1ConcurrentMark::weak_refs_work(bool clear_all_soft_refs) {
|
||||
GCTraceTime(Debug, gc, phases) debug("Class Unloading", _gc_timer_cm);
|
||||
bool purged_classes = SystemDictionary::do_unloading(_gc_timer_cm);
|
||||
_g1h->complete_cleaning(&g1_is_alive, purged_classes);
|
||||
} else {
|
||||
GCTraceTime(Debug, gc, phases) debug("Cleanup", _gc_timer_cm);
|
||||
// No need to clean string table as it is treated as strong roots when
|
||||
// class unloading is disabled.
|
||||
_g1h->partial_cleaning(&g1_is_alive, false, G1StringDedup::is_enabled());
|
||||
} else if (StringDedup::is_enabled()) {
|
||||
GCTraceTime(Debug, gc, phases) debug("String Deduplication", _gc_timer_cm);
|
||||
_g1h->string_dedup_cleaning(&g1_is_alive, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -224,10 +224,10 @@ void G1FullCollector::phase1_mark_live_objects() {
|
||||
// Unload classes and purge the SystemDictionary.
|
||||
bool purged_class = SystemDictionary::do_unloading(scope()->timer());
|
||||
_heap->complete_cleaning(&_is_alive, purged_class);
|
||||
} else {
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: String and Symbol Tables Cleanup", scope()->timer());
|
||||
// If no class unloading just clean out strings.
|
||||
_heap->partial_cleaning(&_is_alive, true, G1StringDedup::is_enabled());
|
||||
} else if (G1StringDedup::is_enabled()) {
|
||||
GCTraceTime(Debug, gc, phases) debug("Phase 1: String Dedup Cleanup", scope()->timer());
|
||||
// If no class unloading just clean out string deduplication data.
|
||||
_heap->string_dedup_cleaning(&_is_alive, NULL);
|
||||
}
|
||||
|
||||
scope()->tracer()->report_object_count_after_gc(&_is_alive);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -86,7 +86,7 @@ G1FullGCAdjustTask::G1FullGCAdjustTask(G1FullCollector* collector) :
|
||||
_weak_proc_task(collector->workers()),
|
||||
_hrclaimer(collector->workers()),
|
||||
_adjust(),
|
||||
_adjust_string_dedup(NULL, &_adjust, G1StringDedup::is_enabled()) {
|
||||
_string_dedup_cleaning_task(NULL, &_adjust, false) {
|
||||
// Need cleared claim bits for the roots processing
|
||||
ClassLoaderDataGraph::clear_claimed_marks();
|
||||
}
|
||||
@ -110,15 +110,10 @@ void G1FullGCAdjustTask::work(uint worker_id) {
|
||||
|
||||
CLDToOopClosure adjust_cld(&_adjust, ClassLoaderData::_claim_strong);
|
||||
CodeBlobToOopClosure adjust_code(&_adjust, CodeBlobToOopClosure::FixRelocations);
|
||||
_root_processor.process_all_roots(
|
||||
&_adjust,
|
||||
&adjust_cld,
|
||||
&adjust_code);
|
||||
_root_processor.process_all_roots(&_adjust, &adjust_cld, &adjust_code);
|
||||
|
||||
// Adjust string dedup if enabled.
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1StringDedup::parallel_unlink(&_adjust_string_dedup, worker_id);
|
||||
}
|
||||
// Adjust string dedup data structures.
|
||||
_string_dedup_cleaning_task.work(worker_id);
|
||||
|
||||
// Now adjust pointers region by region
|
||||
G1AdjustRegionClosure blk(collector()->mark_bitmap(), worker_id);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -30,6 +30,7 @@
|
||||
#include "gc/g1/g1RootProcessor.hpp"
|
||||
#include "gc/g1/g1StringDedup.hpp"
|
||||
#include "gc/g1/heapRegionManager.hpp"
|
||||
#include "gc/shared/parallelCleaning.hpp"
|
||||
#include "gc/shared/weakProcessorPhaseTimes.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "utilities/ticks.hpp"
|
||||
@ -42,7 +43,7 @@ class G1FullGCAdjustTask : public G1FullGCTask {
|
||||
WeakProcessor::Task _weak_proc_task;
|
||||
HeapRegionClaimer _hrclaimer;
|
||||
G1AdjustClosure _adjust;
|
||||
G1StringDedupUnlinkOrOopsDoClosure _adjust_string_dedup;
|
||||
StringDedupCleaningTask _string_dedup_cleaning_task;
|
||||
|
||||
public:
|
||||
G1FullGCAdjustTask(G1FullCollector* collector);
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -49,15 +49,13 @@ void G1FullGCMarkTask::work(uint worker_id) {
|
||||
MarkingCodeBlobClosure code_closure(marker->mark_closure(), !CodeBlobToOopClosure::FixRelocations);
|
||||
|
||||
if (ClassUnloading) {
|
||||
_root_processor.process_strong_roots(
|
||||
marker->mark_closure(),
|
||||
marker->cld_closure(),
|
||||
&code_closure);
|
||||
_root_processor.process_strong_roots(marker->mark_closure(),
|
||||
marker->cld_closure(),
|
||||
&code_closure);
|
||||
} else {
|
||||
_root_processor.process_all_roots_no_string_table(
|
||||
marker->mark_closure(),
|
||||
marker->cld_closure(),
|
||||
&code_closure);
|
||||
_root_processor.process_all_roots(marker->mark_closure(),
|
||||
marker->cld_closure(),
|
||||
&code_closure);
|
||||
}
|
||||
|
||||
// Mark stack is populated, now process and drain it.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2013, 2019, 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
|
||||
@ -53,7 +53,6 @@ G1GCPhaseTimes::G1GCPhaseTimes(STWGCTimer* gc_timer, uint max_gc_threads) :
|
||||
|
||||
// Root scanning phases
|
||||
_gc_par_phases[ThreadRoots] = new WorkerDataArray<double>(max_gc_threads, "Thread Roots (ms):");
|
||||
_gc_par_phases[StringTableRoots] = new WorkerDataArray<double>(max_gc_threads, "StringTable Roots (ms):");
|
||||
_gc_par_phases[UniverseRoots] = new WorkerDataArray<double>(max_gc_threads, "Universe Roots (ms):");
|
||||
_gc_par_phases[JNIRoots] = new WorkerDataArray<double>(max_gc_threads, "JNI Handles Roots (ms):");
|
||||
_gc_par_phases[ObjectSynchronizerRoots] = new WorkerDataArray<double>(max_gc_threads, "ObjectSynchronizer Roots (ms):");
|
||||
@ -136,7 +135,7 @@ void G1GCPhaseTimes::reset() {
|
||||
_cur_strong_code_root_purge_time_ms = 0.0;
|
||||
_cur_evac_fail_recalc_used = 0.0;
|
||||
_cur_evac_fail_remove_self_forwards = 0.0;
|
||||
_cur_string_dedup_fixup_time_ms = 0.0;
|
||||
_cur_string_deduplication_time_ms = 0.0;
|
||||
_cur_prepare_tlab_time_ms = 0.0;
|
||||
_cur_resize_tlab_time_ms = 0.0;
|
||||
_cur_derived_pointer_table_update_time_ms = 0.0;
|
||||
@ -290,12 +289,12 @@ void G1GCPhaseTimes::log_phase(WorkerDataArray<double>* phase, uint indent, outp
|
||||
}
|
||||
}
|
||||
|
||||
void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase) const {
|
||||
void G1GCPhaseTimes::debug_phase(WorkerDataArray<double>* phase, uint extra_indent) const {
|
||||
LogTarget(Debug, gc, phases) lt;
|
||||
if (lt.is_enabled()) {
|
||||
ResourceMark rm;
|
||||
LogStream ls(lt);
|
||||
log_phase(phase, 2, &ls, true);
|
||||
log_phase(phase, 2 + extra_indent, &ls, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -417,7 +416,7 @@ double G1GCPhaseTimes::print_post_evacuate_collection_set() const {
|
||||
_recorded_total_free_cset_time_ms +
|
||||
_cur_fast_reclaim_humongous_time_ms +
|
||||
_cur_expand_heap_time_ms +
|
||||
_cur_string_dedup_fixup_time_ms;
|
||||
_cur_string_deduplication_time_ms;
|
||||
|
||||
info_time("Post Evacuate Collection Set", sum_ms);
|
||||
|
||||
@ -430,9 +429,9 @@ double G1GCPhaseTimes::print_post_evacuate_collection_set() const {
|
||||
_weak_phase_times.log_print(2);
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
debug_time("String Dedup Fixup", _cur_string_dedup_fixup_time_ms);
|
||||
debug_phase(_gc_par_phases[StringDedupQueueFixup]);
|
||||
debug_phase(_gc_par_phases[StringDedupTableFixup]);
|
||||
debug_time("String Deduplication", _cur_string_deduplication_time_ms);
|
||||
debug_phase(_gc_par_phases[StringDedupQueueFixup], 1);
|
||||
debug_phase(_gc_par_phases[StringDedupTableFixup], 1);
|
||||
}
|
||||
|
||||
if (G1CollectedHeap::heap()->evacuation_failed()) {
|
||||
@ -497,7 +496,6 @@ const char* G1GCPhaseTimes::phase_name(GCParPhases phase) {
|
||||
"GCWorkerStart",
|
||||
"ExtRootScan",
|
||||
"ThreadRoots",
|
||||
"StringTableRoots",
|
||||
"UniverseRoots",
|
||||
"JNIRoots",
|
||||
"ObjectSynchronizerRoots",
|
||||
|
@ -48,7 +48,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
GCWorkerStart,
|
||||
ExtRootScan,
|
||||
ThreadRoots,
|
||||
StringTableRoots,
|
||||
UniverseRoots,
|
||||
JNIRoots,
|
||||
ObjectSynchronizerRoots,
|
||||
@ -104,8 +103,6 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
private:
|
||||
// Markers for grouping the phases in the GCPhases enum above
|
||||
static const int GCMainParPhasesLast = GCWorkerEnd;
|
||||
static const int StringDedupPhasesFirst = StringDedupQueueFixup;
|
||||
static const int StringDedupPhasesLast = StringDedupTableFixup;
|
||||
|
||||
WorkerDataArray<double>* _gc_par_phases[GCParPhasesSentinel];
|
||||
|
||||
@ -134,7 +131,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
double _cur_evac_fail_recalc_used;
|
||||
double _cur_evac_fail_remove_self_forwards;
|
||||
|
||||
double _cur_string_dedup_fixup_time_ms;
|
||||
double _cur_string_deduplication_time_ms;
|
||||
|
||||
double _cur_prepare_tlab_time_ms;
|
||||
double _cur_resize_tlab_time_ms;
|
||||
@ -187,7 +184,7 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
void details(T* phase, const char* indent) const;
|
||||
|
||||
void log_phase(WorkerDataArray<double>* phase, uint indent, outputStream* out, bool print_sum) const;
|
||||
void debug_phase(WorkerDataArray<double>* phase) const;
|
||||
void debug_phase(WorkerDataArray<double>* phase, uint extra_indent = 0) const;
|
||||
void trace_phase(WorkerDataArray<double>* phase, bool print_sum = true) const;
|
||||
|
||||
void info_time(const char* name, double value) const;
|
||||
@ -272,8 +269,8 @@ class G1GCPhaseTimes : public CHeapObj<mtGC> {
|
||||
_cur_evac_fail_remove_self_forwards = ms;
|
||||
}
|
||||
|
||||
void record_string_dedup_fixup_time(double ms) {
|
||||
_cur_string_dedup_fixup_time_ms = ms;
|
||||
void record_string_deduplication_time(double ms) {
|
||||
_cur_string_deduplication_time_ms = ms;
|
||||
}
|
||||
|
||||
void record_ref_proc_time(double ms) {
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2016, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2016, 2019, 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
|
||||
@ -490,9 +490,7 @@ void G1HeapVerifier::verify(VerifyOption vo) {
|
||||
|
||||
{
|
||||
G1RootProcessor root_processor(_g1h, 1);
|
||||
root_processor.process_all_roots(&rootsCl,
|
||||
&cldCl,
|
||||
&blobsCl);
|
||||
root_processor.process_all_roots(&rootsCl, &cldCl, &blobsCl);
|
||||
}
|
||||
|
||||
bool failures = rootsCl.failures() || codeRootsCl.failures();
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2015, 2019, 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
|
||||
@ -90,7 +90,6 @@ void G1RootProcessor::evacuate_roots(G1ParScanThreadState* pss, uint worker_i) {
|
||||
}
|
||||
|
||||
process_vm_roots(closures, phase_times, worker_i);
|
||||
process_string_table_roots(closures, phase_times, worker_i);
|
||||
|
||||
{
|
||||
// Now the CM ref_processor roots.
|
||||
@ -188,34 +187,17 @@ public:
|
||||
|
||||
void G1RootProcessor::process_all_roots(OopClosure* oops,
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs,
|
||||
bool process_string_table) {
|
||||
CodeBlobClosure* blobs) {
|
||||
AllRootsClosures closures(oops, clds);
|
||||
|
||||
process_java_roots(&closures, NULL, 0);
|
||||
process_vm_roots(&closures, NULL, 0);
|
||||
|
||||
if (process_string_table) {
|
||||
process_string_table_roots(&closures, NULL, 0);
|
||||
}
|
||||
process_code_cache_roots(blobs, NULL, 0);
|
||||
|
||||
_process_strong_tasks.all_tasks_completed(n_workers());
|
||||
}
|
||||
|
||||
void G1RootProcessor::process_all_roots(OopClosure* oops,
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs) {
|
||||
process_all_roots(oops, clds, blobs, true);
|
||||
}
|
||||
|
||||
void G1RootProcessor::process_all_roots_no_string_table(OopClosure* oops,
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs) {
|
||||
assert(!ClassUnloading, "Should only be used when class unloading is disabled");
|
||||
process_all_roots(oops, clds, blobs, false);
|
||||
}
|
||||
|
||||
void G1RootProcessor::process_java_roots(G1RootClosures* closures,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i) {
|
||||
@ -295,16 +277,6 @@ void G1RootProcessor::process_vm_roots(G1RootClosures* closures,
|
||||
}
|
||||
}
|
||||
|
||||
void G1RootProcessor::process_string_table_roots(G1RootClosures* closures,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i) {
|
||||
assert(closures->weak_oops() != NULL, "Should only be called when all roots are processed");
|
||||
G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::StringTableRoots, worker_i);
|
||||
// All threads execute the following. A specific chunk of buckets
|
||||
// from the StringTable are the individual tasks.
|
||||
StringTable::possibly_parallel_oops_do(&_par_state_string, closures->weak_oops());
|
||||
}
|
||||
|
||||
void G1RootProcessor::process_code_cache_roots(CodeBlobClosure* code_closure,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i) {
|
||||
|
@ -75,11 +75,6 @@ class G1RootProcessor : public StackObj {
|
||||
void worker_has_discovered_all_strong_classes();
|
||||
void wait_until_all_strong_classes_discovered();
|
||||
|
||||
void process_all_roots(OopClosure* oops,
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs,
|
||||
bool process_string_table);
|
||||
|
||||
void process_java_roots(G1RootClosures* closures,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i);
|
||||
@ -88,10 +83,6 @@ class G1RootProcessor : public StackObj {
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i);
|
||||
|
||||
void process_string_table_roots(G1RootClosures* closures,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i);
|
||||
|
||||
void process_code_cache_roots(CodeBlobClosure* code_closure,
|
||||
G1GCPhaseTimes* phase_times,
|
||||
uint worker_i);
|
||||
@ -101,7 +92,7 @@ public:
|
||||
|
||||
// Apply correct closures from pss to the strongly and weakly reachable roots in the system
|
||||
// in a single pass.
|
||||
// Record and report timing measurements for sub phases using the worker_i
|
||||
// Record and report timing measurements for sub phases using worker_id.
|
||||
void evacuate_roots(G1ParScanThreadState* pss, uint worker_id);
|
||||
|
||||
// Apply oops, clds and blobs to all strongly reachable roots in the system
|
||||
@ -114,13 +105,6 @@ public:
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs);
|
||||
|
||||
// Apply oops, clds and blobs to strongly and weakly reachable roots in the system,
|
||||
// the only thing different from process_all_roots is that we skip the string table
|
||||
// to avoid keeping every string live when doing class unloading.
|
||||
void process_all_roots_no_string_table(OopClosure* oops,
|
||||
CLDClosure* clds,
|
||||
CodeBlobClosure* blobs);
|
||||
|
||||
// Number of worker threads used by the root processor.
|
||||
uint n_workers() const;
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2019, 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
|
||||
@ -89,53 +89,3 @@ void G1StringDedup::enqueue_from_evacuation(bool from_young, bool to_young, uint
|
||||
}
|
||||
}
|
||||
|
||||
void G1StringDedup::oops_do(OopClosure* keep_alive) {
|
||||
assert(is_enabled(), "String deduplication not enabled");
|
||||
unlink_or_oops_do(NULL, keep_alive, true /* allow_resize_and_rehash */);
|
||||
}
|
||||
|
||||
void G1StringDedup::parallel_unlink(G1StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id) {
|
||||
assert(is_enabled(), "String deduplication not enabled");
|
||||
StringDedupQueue::unlink_or_oops_do(unlink);
|
||||
StringDedupTable::unlink_or_oops_do(unlink, worker_id);
|
||||
}
|
||||
|
||||
//
|
||||
// Task for parallel unlink_or_oops_do() operation on the deduplication queue
|
||||
// and table.
|
||||
//
|
||||
class G1StringDedupUnlinkOrOopsDoTask : public AbstractGangTask {
|
||||
private:
|
||||
G1StringDedupUnlinkOrOopsDoClosure _cl;
|
||||
G1GCPhaseTimes* _phase_times;
|
||||
|
||||
public:
|
||||
G1StringDedupUnlinkOrOopsDoTask(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
bool allow_resize_and_rehash,
|
||||
G1GCPhaseTimes* phase_times) :
|
||||
AbstractGangTask("G1StringDedupUnlinkOrOopsDoTask"),
|
||||
_cl(is_alive, keep_alive, allow_resize_and_rehash), _phase_times(phase_times) { }
|
||||
|
||||
virtual void work(uint worker_id) {
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupQueueFixup, worker_id);
|
||||
StringDedupQueue::unlink_or_oops_do(&_cl);
|
||||
}
|
||||
{
|
||||
G1GCParPhaseTimesTracker x(_phase_times, G1GCPhaseTimes::StringDedupTableFixup, worker_id);
|
||||
StringDedupTable::unlink_or_oops_do(&_cl, worker_id);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
void G1StringDedup::unlink_or_oops_do(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
bool allow_resize_and_rehash,
|
||||
G1GCPhaseTimes* phase_times) {
|
||||
assert(is_enabled(), "String deduplication not enabled");
|
||||
|
||||
G1StringDedupUnlinkOrOopsDoTask task(is_alive, keep_alive, allow_resize_and_rehash, phase_times);
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
g1h->workers()->run_task(&task);
|
||||
}
|
||||
|
@ -78,35 +78,6 @@ public:
|
||||
static void enqueue_from_mark(oop java_string, uint worker_id);
|
||||
static void enqueue_from_evacuation(bool from_young, bool to_young,
|
||||
unsigned int queue, oop java_string);
|
||||
|
||||
static void oops_do(OopClosure* keep_alive);
|
||||
static void parallel_unlink(G1StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id);
|
||||
static void unlink_or_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive,
|
||||
bool allow_resize_and_rehash, G1GCPhaseTimes* phase_times = NULL);
|
||||
};
|
||||
|
||||
//
|
||||
// This closure encapsulates the state and the closures needed when scanning
|
||||
// the deduplication queue and table during the unlink_or_oops_do() operation.
|
||||
// A single instance of this closure is created and then shared by all worker
|
||||
// threads participating in the scan.
|
||||
//
|
||||
class G1StringDedupUnlinkOrOopsDoClosure : public StringDedupUnlinkOrOopsDoClosure {
|
||||
public:
|
||||
G1StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
bool allow_resize_and_rehash) :
|
||||
StringDedupUnlinkOrOopsDoClosure(is_alive, keep_alive) {
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1StringDedup::gc_prologue(allow_resize_and_rehash);
|
||||
}
|
||||
}
|
||||
|
||||
~G1StringDedupUnlinkOrOopsDoClosure() {
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1StringDedup::gc_epilogue();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_G1_G1STRINGDEDUP_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -566,12 +566,6 @@ void PSMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
Klass::clean_weak_klass_links(purged_class);
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub String Table", _gc_timer);
|
||||
// Delete entries for dead interned strings.
|
||||
StringTable::unlink(is_alive_closure());
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", _gc_timer);
|
||||
// Clean up unreferenced symbols in symbol table.
|
||||
@ -630,7 +624,6 @@ void PSMarkSweep::mark_sweep_phase3() {
|
||||
CodeBlobToOopClosure adjust_from_blobs(adjust_pointer_closure(), CodeBlobToOopClosure::FixRelocations);
|
||||
CodeCache::blobs_do(&adjust_from_blobs);
|
||||
AOTLoader::oops_do(adjust_pointer_closure());
|
||||
StringTable::oops_do(adjust_pointer_closure());
|
||||
ref_processor()->weak_oops_do(adjust_pointer_closure());
|
||||
PSScavenge::reference_processor()->weak_oops_do(adjust_pointer_closure());
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2005, 2019, 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
|
||||
@ -2184,12 +2184,6 @@ void PSParallelCompact::marking_phase(ParCompactionManager* cm,
|
||||
Klass::clean_weak_klass_links(purged_class);
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub String Table", &_gc_timer);
|
||||
// Delete entries for dead interned strings.
|
||||
StringTable::unlink(is_alive_closure());
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", &_gc_timer);
|
||||
// Clean up unreferenced symbols in symbol table.
|
||||
@ -2226,7 +2220,6 @@ void PSParallelCompact::adjust_roots(ParCompactionManager* cm) {
|
||||
CodeBlobToOopClosure adjust_from_blobs(&oop_closure, CodeBlobToOopClosure::FixRelocations);
|
||||
CodeCache::blobs_do(&adjust_from_blobs);
|
||||
AOTLoader::oops_do(&oop_closure);
|
||||
StringTable::oops_do(&oop_closure);
|
||||
ref_processor()->weak_oops_do(&oop_closure);
|
||||
// Roots were visited so references into the young gen in roots
|
||||
// may have been scanned. Process them also.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2002, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2002, 2019, 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
|
||||
@ -430,12 +430,6 @@ bool PSScavenge::invoke_no_policy() {
|
||||
WeakProcessor::weak_oops_do(&_is_alive_closure, &root_closure);
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) tm("Scrub String Table", &_gc_timer);
|
||||
// Unlink any dead interned Strings and process the remaining live ones.
|
||||
StringTable::unlink_or_oops_do(&_is_alive_closure, &root_closure);
|
||||
}
|
||||
|
||||
// Verify that usage of root_closure didn't copy any objects.
|
||||
assert(promotion_manager->stacks_empty(),"stacks should be empty at this point");
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2001, 2019, 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
|
||||
@ -239,12 +239,6 @@ void GenMarkSweep::mark_sweep_phase1(bool clear_all_softrefs) {
|
||||
Klass::clean_weak_klass_links(purged_class);
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub String Table", gc_timer());
|
||||
// Delete entries for dead interned strings.
|
||||
StringTable::unlink(&is_alive);
|
||||
}
|
||||
|
||||
{
|
||||
GCTraceTime(Debug, gc, phases) t("Scrub Symbol Table", gc_timer());
|
||||
// Clean up unreferenced symbols in symbol table.
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2000, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2000, 2019, 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
|
||||
@ -849,33 +849,14 @@ void GenCollectedHeap::process_roots(StrongRootsScope* scope,
|
||||
}
|
||||
}
|
||||
|
||||
void GenCollectedHeap::process_string_table_roots(StrongRootsScope* scope,
|
||||
OopClosure* root_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string) {
|
||||
assert(root_closure != NULL, "Must be set");
|
||||
// All threads execute the following. A specific chunk of buckets
|
||||
// from the StringTable are the individual tasks.
|
||||
|
||||
// Either we should be single threaded or have a ParState
|
||||
assert((scope->n_threads() <= 1) || par_state_string != NULL, "Parallel but no ParState");
|
||||
|
||||
if (scope->n_threads() > 1) {
|
||||
StringTable::possibly_parallel_oops_do(par_state_string, root_closure);
|
||||
} else {
|
||||
StringTable::oops_do(root_closure);
|
||||
}
|
||||
}
|
||||
|
||||
void GenCollectedHeap::young_process_roots(StrongRootsScope* scope,
|
||||
OopsInGenClosure* root_closure,
|
||||
OopsInGenClosure* old_gen_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string) {
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, CodeBlobToOopClosure::FixRelocations);
|
||||
|
||||
process_roots(scope, SO_ScavengeCodeCache, root_closure,
|
||||
cld_closure, cld_closure, &mark_code_closure);
|
||||
process_string_table_roots(scope, root_closure, par_state_string);
|
||||
|
||||
if (_process_strong_tasks->try_claim_task(GCH_PS_younger_gens)) {
|
||||
root_closure->reset_generation();
|
||||
@ -895,19 +876,11 @@ void GenCollectedHeap::full_process_roots(StrongRootsScope* scope,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string) {
|
||||
CLDClosure* cld_closure) {
|
||||
MarkingCodeBlobClosure mark_code_closure(root_closure, is_adjust_phase);
|
||||
CLDClosure* weak_cld_closure = only_strong_roots ? NULL : cld_closure;
|
||||
|
||||
process_roots(scope, so, root_closure, cld_closure, weak_cld_closure, &mark_code_closure);
|
||||
if (is_adjust_phase) {
|
||||
// We never treat the string table as roots during marking
|
||||
// for the full gc, so we only need to process it during
|
||||
// the adjust phase.
|
||||
process_string_table_roots(scope, root_closure, par_state_string);
|
||||
}
|
||||
|
||||
_process_strong_tasks->all_tasks_completed(scope->n_threads());
|
||||
}
|
||||
|
||||
|
@ -400,10 +400,6 @@ public:
|
||||
CLDClosure* weak_cld_closure,
|
||||
CodeBlobToOopClosure* code_roots);
|
||||
|
||||
void process_string_table_roots(StrongRootsScope* scope,
|
||||
OopClosure* root_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string);
|
||||
|
||||
// Accessor for memory state verification support
|
||||
NOT_PRODUCT(
|
||||
virtual size_t skip_header_HeapWords() { return 0; }
|
||||
@ -416,16 +412,14 @@ public:
|
||||
void young_process_roots(StrongRootsScope* scope,
|
||||
OopsInGenClosure* root_closure,
|
||||
OopsInGenClosure* old_gen_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string = NULL);
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
void full_process_roots(StrongRootsScope* scope,
|
||||
bool is_adjust_phase,
|
||||
ScanningOption so,
|
||||
bool only_strong_roots,
|
||||
OopsInGenClosure* root_closure,
|
||||
CLDClosure* cld_closure,
|
||||
OopStorage::ParState<false, false>* par_state_string = NULL);
|
||||
CLDClosure* cld_closure);
|
||||
|
||||
// Apply "root_closure" to all the weak roots of the system.
|
||||
// These include JNI weak roots, string table,
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -31,48 +31,35 @@
|
||||
#include "memory/resourceArea.hpp"
|
||||
#include "logging/log.hpp"
|
||||
|
||||
StringCleaningTask::StringCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure, bool process_strings) :
|
||||
AbstractGangTask("String Unlinking"),
|
||||
_is_alive(is_alive),
|
||||
_dedup_closure(dedup_closure),
|
||||
_par_state_string(StringTable::weak_storage()),
|
||||
_initial_string_table_size((int) StringTable::the_table()->table_size()),
|
||||
_process_strings(process_strings), _strings_processed(0), _strings_removed(0) {
|
||||
StringDedupCleaningTask::StringDedupCleaningTask(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive,
|
||||
bool resize_table) :
|
||||
AbstractGangTask("String Dedup Cleaning"),
|
||||
_dedup_closure(is_alive, keep_alive) {
|
||||
|
||||
if (process_strings) {
|
||||
StringTable::reset_dead_counter();
|
||||
if (StringDedup::is_enabled()) {
|
||||
StringDedup::gc_prologue(resize_table);
|
||||
}
|
||||
}
|
||||
|
||||
StringCleaningTask::~StringCleaningTask() {
|
||||
log_info(gc, stringtable)(
|
||||
"Cleaned string table, "
|
||||
"strings: " SIZE_FORMAT " processed, " SIZE_FORMAT " removed",
|
||||
strings_processed(), strings_removed());
|
||||
if (_process_strings) {
|
||||
StringTable::finish_dead_counter();
|
||||
StringDedupCleaningTask::~StringDedupCleaningTask() {
|
||||
if (StringDedup::is_enabled()) {
|
||||
StringDedup::gc_epilogue();
|
||||
}
|
||||
}
|
||||
|
||||
void StringCleaningTask::work(uint worker_id) {
|
||||
size_t strings_processed = 0;
|
||||
size_t strings_removed = 0;
|
||||
if (_process_strings) {
|
||||
StringTable::possibly_parallel_unlink(&_par_state_string, _is_alive, &strings_processed, &strings_removed);
|
||||
Atomic::add(strings_processed, &_strings_processed);
|
||||
Atomic::add(strings_removed, &_strings_removed);
|
||||
}
|
||||
if (_dedup_closure != NULL) {
|
||||
StringDedup::parallel_unlink(_dedup_closure, worker_id);
|
||||
void StringDedupCleaningTask::work(uint worker_id) {
|
||||
if (StringDedup::is_enabled()) {
|
||||
StringDedup::parallel_unlink(&_dedup_closure, worker_id);
|
||||
}
|
||||
}
|
||||
|
||||
CodeCacheUnloadingTask::CodeCacheUnloadingTask(uint num_workers, BoolObjectClosure* is_alive, bool unloading_occurred) :
|
||||
_unloading_scope(is_alive),
|
||||
_unloading_occurred(unloading_occurred),
|
||||
_num_workers(num_workers),
|
||||
_first_nmethod(NULL),
|
||||
_claimed_nmethod(NULL) {
|
||||
_unloading_scope(is_alive),
|
||||
_unloading_occurred(unloading_occurred),
|
||||
_num_workers(num_workers),
|
||||
_first_nmethod(NULL),
|
||||
_claimed_nmethod(NULL) {
|
||||
// Get first alive nmethod
|
||||
CompiledMethodIterator iter(CompiledMethodIterator::only_alive);
|
||||
if(iter.next()) {
|
||||
@ -175,10 +162,12 @@ void KlassCleaningTask::work() {
|
||||
}
|
||||
|
||||
ParallelCleaningTask::ParallelCleaningTask(BoolObjectClosure* is_alive,
|
||||
StringDedupUnlinkOrOopsDoClosure* dedup_closure, uint num_workers, bool unloading_occurred) :
|
||||
uint num_workers,
|
||||
bool unloading_occurred,
|
||||
bool resize_dedup_table) :
|
||||
AbstractGangTask("Parallel Cleaning"),
|
||||
_unloading_occurred(unloading_occurred),
|
||||
_string_task(is_alive, StringDedup::is_enabled() ? dedup_closure : NULL, true),
|
||||
_string_dedup_task(is_alive, NULL, resize_dedup_table),
|
||||
_code_cache_task(num_workers, is_alive, unloading_occurred),
|
||||
_klass_cleaning_task() {
|
||||
}
|
||||
@ -188,8 +177,8 @@ void ParallelCleaningTask::work(uint worker_id) {
|
||||
// Do first pass of code cache cleaning.
|
||||
_code_cache_task.work(worker_id);
|
||||
|
||||
// Clean the Strings and Symbols.
|
||||
_string_task.work(worker_id);
|
||||
// Clean the string dedup data structures.
|
||||
_string_dedup_task.work(worker_id);
|
||||
|
||||
// Clean all klasses that were not unloaded.
|
||||
// The weak metadata in klass doesn't need to be
|
||||
|
@ -33,27 +33,14 @@
|
||||
|
||||
class ParallelCleaningTask;
|
||||
|
||||
class StringCleaningTask : public AbstractGangTask {
|
||||
private:
|
||||
BoolObjectClosure* _is_alive;
|
||||
StringDedupUnlinkOrOopsDoClosure * const _dedup_closure;
|
||||
|
||||
OopStorage::ParState<false /* concurrent */, false /* const */> _par_state_string;
|
||||
|
||||
int _initial_string_table_size;
|
||||
|
||||
bool _process_strings;
|
||||
volatile size_t _strings_processed;
|
||||
volatile size_t _strings_removed;
|
||||
class StringDedupCleaningTask : public AbstractGangTask {
|
||||
StringDedupUnlinkOrOopsDoClosure _dedup_closure;
|
||||
|
||||
public:
|
||||
StringCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure, bool process_strings);
|
||||
~StringCleaningTask();
|
||||
StringDedupCleaningTask(BoolObjectClosure* is_alive, OopClosure* keep_alive, bool resize_table);
|
||||
~StringDedupCleaningTask();
|
||||
|
||||
void work(uint worker_id);
|
||||
|
||||
size_t strings_processed() const { return _strings_processed; }
|
||||
size_t strings_removed() const { return _strings_removed; }
|
||||
};
|
||||
|
||||
class CodeCacheUnloadingTask {
|
||||
@ -100,18 +87,21 @@ public:
|
||||
void work();
|
||||
};
|
||||
|
||||
// To minimize the remark pause times, the tasks below are done in parallel.
|
||||
// Do cleanup of some weakly held data in the same parallel task.
|
||||
// Assumes a non-moving context.
|
||||
class ParallelCleaningTask : public AbstractGangTask {
|
||||
private:
|
||||
bool _unloading_occurred;
|
||||
StringCleaningTask _string_task;
|
||||
CodeCacheUnloadingTask _code_cache_task;
|
||||
KlassCleaningTask _klass_cleaning_task;
|
||||
bool _unloading_occurred;
|
||||
StringDedupCleaningTask _string_dedup_task;
|
||||
CodeCacheUnloadingTask _code_cache_task;
|
||||
KlassCleaningTask _klass_cleaning_task;
|
||||
|
||||
public:
|
||||
// The constructor is run in the VMThread.
|
||||
ParallelCleaningTask(BoolObjectClosure* is_alive, StringDedupUnlinkOrOopsDoClosure* dedup_closure,
|
||||
uint num_workers, bool unloading_occurred);
|
||||
ParallelCleaningTask(BoolObjectClosure* is_alive,
|
||||
uint num_workers,
|
||||
bool unloading_occurred,
|
||||
bool resize_dedup_table);
|
||||
|
||||
void work(uint worker_id);
|
||||
};
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2014, 2019, 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
|
||||
@ -53,7 +53,6 @@ void StringDedup::deduplicate(oop java_string) {
|
||||
StringDedupTable::deduplicate(java_string, &dummy);
|
||||
}
|
||||
|
||||
|
||||
void StringDedup::parallel_unlink(StringDedupUnlinkOrOopsDoClosure* unlink, uint worker_id) {
|
||||
assert(is_enabled(), "String deduplication not enabled");
|
||||
StringDedupQueue::unlink_or_oops_do(unlink);
|
||||
@ -80,5 +79,8 @@ void StringDedup::verify() {
|
||||
|
||||
StringDedupUnlinkOrOopsDoClosure::StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive) :
|
||||
_is_alive(is_alive), _keep_alive(keep_alive) {
|
||||
_always_true(),
|
||||
_do_nothing(),
|
||||
_is_alive(is_alive != NULL ? is_alive : &_always_true),
|
||||
_keep_alive(keep_alive != NULL ? keep_alive : &_do_nothing) {
|
||||
}
|
||||
|
@ -113,30 +113,18 @@ protected:
|
||||
// the deduplication queue and table during the unlink_or_oops_do() operation.
|
||||
//
|
||||
class StringDedupUnlinkOrOopsDoClosure : public StackObj {
|
||||
private:
|
||||
AlwaysTrueClosure _always_true;
|
||||
DoNothingClosure _do_nothing;
|
||||
BoolObjectClosure* _is_alive;
|
||||
OopClosure* _keep_alive;
|
||||
|
||||
public:
|
||||
StringDedupUnlinkOrOopsDoClosure(BoolObjectClosure* is_alive,
|
||||
OopClosure* keep_alive);
|
||||
OopClosure* keep_alive);
|
||||
|
||||
// Applies and returns the result from the is_alive closure, or
|
||||
// returns true if no such closure was provided.
|
||||
bool is_alive(oop o) {
|
||||
if (_is_alive != NULL) {
|
||||
return _is_alive->do_object_b(o);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
bool is_alive(oop o) { return _is_alive->do_object_b(o); }
|
||||
|
||||
// Applies the keep_alive closure, or does nothing if no such
|
||||
// closure was provided.
|
||||
void keep_alive(oop* p) {
|
||||
if (_keep_alive != NULL) {
|
||||
_keep_alive->do_oop(p);
|
||||
}
|
||||
}
|
||||
void keep_alive(oop* p) { _keep_alive->do_oop(p); }
|
||||
};
|
||||
|
||||
#endif // SHARE_GC_SHARED_STRINGDEDUP_STRINGDEDUP_HPP
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2017, 2019, 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
|
||||
@ -23,9 +23,9 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "gc/shared/oopStorageParState.inline.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
#include "gc/shared/weakProcessor.inline.hpp"
|
||||
#include "gc/shared/weakProcessorPhases.hpp"
|
||||
#include "gc/shared/weakProcessorPhaseTimes.hpp"
|
||||
@ -35,13 +35,19 @@
|
||||
#include "utilities/macros.hpp"
|
||||
|
||||
void WeakProcessor::weak_oops_do(BoolObjectClosure* is_alive, OopClosure* keep_alive) {
|
||||
StringTable::reset_dead_counter();
|
||||
CountingIsAliveClosure<BoolObjectClosure> cl(is_alive);
|
||||
FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
|
||||
if (WeakProcessorPhases::is_serial(phase)) {
|
||||
WeakProcessorPhases::processor(phase)(is_alive, keep_alive);
|
||||
WeakProcessorPhases::processor(phase)(&cl, keep_alive);
|
||||
} else {
|
||||
WeakProcessorPhases::oop_storage(phase)->weak_oops_do(is_alive, keep_alive);
|
||||
WeakProcessorPhases::oop_storage(phase)->weak_oops_do(&cl, keep_alive);
|
||||
}
|
||||
if (WeakProcessorPhases::is_stringtable(phase)) {
|
||||
StringTable::inc_dead_counter(cl.num_dead());
|
||||
}
|
||||
}
|
||||
StringTable::finish_dead_counter();
|
||||
}
|
||||
|
||||
void WeakProcessor::oops_do(OopClosure* closure) {
|
||||
@ -93,6 +99,7 @@ void WeakProcessor::Task::initialize() {
|
||||
OopStorage* storage = WeakProcessorPhases::oop_storage(phase);
|
||||
new (states++) StorageState(storage, _nworkers);
|
||||
}
|
||||
StringTable::reset_dead_counter();
|
||||
}
|
||||
|
||||
WeakProcessor::Task::Task(uint nworkers) :
|
||||
@ -122,6 +129,7 @@ WeakProcessor::Task::~Task() {
|
||||
}
|
||||
FREE_C_HEAP_ARRAY(StorageState, _storage_states);
|
||||
}
|
||||
StringTable::finish_dead_counter();
|
||||
}
|
||||
|
||||
void WeakProcessor::GangTask::work(uint worker_id) {
|
||||
|
@ -25,6 +25,7 @@
|
||||
#ifndef SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
|
||||
#define SHARE_GC_SHARED_WEAKPROCESSOR_INLINE_HPP
|
||||
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "gc/shared/oopStorage.inline.hpp"
|
||||
#include "gc/shared/oopStorageParState.inline.hpp"
|
||||
#include "gc/shared/weakProcessor.hpp"
|
||||
@ -36,6 +37,27 @@
|
||||
class BoolObjectClosure;
|
||||
class OopClosure;
|
||||
|
||||
template<typename T>
|
||||
class CountingIsAliveClosure : public BoolObjectClosure {
|
||||
T* _inner;
|
||||
|
||||
size_t _num_dead;
|
||||
size_t _num_total;
|
||||
|
||||
public:
|
||||
CountingIsAliveClosure(T* cl) : _inner(cl), _num_dead(0), _num_total(0) { }
|
||||
|
||||
virtual bool do_object_b(oop obj) {
|
||||
bool result = _inner->do_object_b(obj);
|
||||
_num_dead += !result;
|
||||
_num_total++;
|
||||
return result;
|
||||
}
|
||||
|
||||
size_t num_dead() const { return _num_dead; }
|
||||
size_t num_total() const { return _num_total; }
|
||||
};
|
||||
|
||||
template<typename IsAlive, typename KeepAlive>
|
||||
void WeakProcessor::Task::work(uint worker_id,
|
||||
IsAlive* is_alive,
|
||||
@ -45,16 +67,26 @@ void WeakProcessor::Task::work(uint worker_id,
|
||||
worker_id, _nworkers);
|
||||
|
||||
FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
|
||||
CountingIsAliveClosure<IsAlive> cl(is_alive);
|
||||
if (WeakProcessorPhases::is_serial(phase)) {
|
||||
uint serial_index = WeakProcessorPhases::serial_index(phase);
|
||||
if (_serial_phases_done.try_claim_task(serial_index)) {
|
||||
WeakProcessorPhaseTimeTracker pt(_phase_times, phase);
|
||||
WeakProcessorPhases::processor(phase)(is_alive, keep_alive);
|
||||
WeakProcessorPhases::processor(phase)(&cl, keep_alive);
|
||||
if (_phase_times != NULL) {
|
||||
_phase_times->record_phase_items(phase, cl.num_dead(), cl.num_total());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
WeakProcessorPhaseTimeTracker pt(_phase_times, phase, worker_id);
|
||||
uint storage_index = WeakProcessorPhases::oop_storage_index(phase);
|
||||
_storage_states[storage_index].weak_oops_do(is_alive, keep_alive);
|
||||
_storage_states[storage_index].weak_oops_do(&cl, keep_alive);
|
||||
if (_phase_times != NULL) {
|
||||
_phase_times->record_worker_items(worker_id, phase, cl.num_dead(), cl.num_total());
|
||||
}
|
||||
}
|
||||
if (WeakProcessorPhases::is_stringtable(phase)) {
|
||||
StringTable::inc_dead_counter(cl.num_dead());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -49,6 +49,7 @@ const double uninitialized_time = -1.0;
|
||||
|
||||
#ifdef ASSERT
|
||||
static bool is_initialized_time(double t) { return t >= 0.0; }
|
||||
static bool is_initialized_items(size_t i) { return i != 0; }
|
||||
#endif // ASSERT
|
||||
|
||||
static void reset_times(double* times, size_t ntimes) {
|
||||
@ -57,28 +58,43 @@ static void reset_times(double* times, size_t ntimes) {
|
||||
}
|
||||
}
|
||||
|
||||
static void reset_items(size_t* items, size_t nitems) {
|
||||
for (size_t i = 0; i < nitems; ++i) {
|
||||
items[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
WeakProcessorPhaseTimes::WeakProcessorPhaseTimes(uint max_threads) :
|
||||
_max_threads(max_threads),
|
||||
_active_workers(0),
|
||||
_total_time_sec(uninitialized_time),
|
||||
_worker_phase_times_sec()
|
||||
_worker_data(),
|
||||
_worker_dead_items(),
|
||||
_worker_total_items()
|
||||
{
|
||||
assert(_max_threads > 0, "max_threads must not be zero");
|
||||
|
||||
reset_times(_phase_times_sec, ARRAY_SIZE(_phase_times_sec));
|
||||
reset_items(_phase_dead_items, ARRAY_SIZE(_phase_dead_items));
|
||||
reset_items(_phase_total_items, ARRAY_SIZE(_phase_total_items));
|
||||
|
||||
if (_max_threads > 1) {
|
||||
WorkerDataArray<double>** wpt = _worker_phase_times_sec;
|
||||
WorkerDataArray<double>** wpt = _worker_data;
|
||||
FOR_EACH_WEAK_PROCESSOR_OOP_STORAGE_PHASE(phase) {
|
||||
const char* description = WeakProcessorPhases::description(phase);
|
||||
*wpt++ = new WorkerDataArray<double>(_max_threads, description);
|
||||
*wpt = new WorkerDataArray<double>(_max_threads, description);
|
||||
(*wpt)->link_thread_work_items(new WorkerDataArray<size_t>(_max_threads, "Dead"), DeadItems);
|
||||
(*wpt)->link_thread_work_items(new WorkerDataArray<size_t>(_max_threads, "Total"), TotalItems);
|
||||
wpt++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
WeakProcessorPhaseTimes::~WeakProcessorPhaseTimes() {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_worker_phase_times_sec); ++i) {
|
||||
delete _worker_phase_times_sec[i];
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_worker_data); ++i) {
|
||||
delete _worker_data[i];
|
||||
delete _worker_dead_items[i];
|
||||
delete _worker_total_items[i];
|
||||
}
|
||||
}
|
||||
|
||||
@ -100,9 +116,11 @@ void WeakProcessorPhaseTimes::reset() {
|
||||
_active_workers = 0;
|
||||
_total_time_sec = uninitialized_time;
|
||||
reset_times(_phase_times_sec, ARRAY_SIZE(_phase_times_sec));
|
||||
reset_items(_phase_dead_items, ARRAY_SIZE(_phase_dead_items));
|
||||
reset_items(_phase_total_items, ARRAY_SIZE(_phase_total_items));
|
||||
if (_max_threads > 1) {
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_worker_phase_times_sec); ++i) {
|
||||
_worker_phase_times_sec[i]->reset();
|
||||
for (size_t i = 0; i < ARRAY_SIZE(_worker_data); ++i) {
|
||||
_worker_data[i]->reset();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -129,10 +147,20 @@ void WeakProcessorPhaseTimes::record_phase_time_sec(WeakProcessorPhase phase, do
|
||||
_phase_times_sec[phase_index(phase)] = time_sec;
|
||||
}
|
||||
|
||||
void WeakProcessorPhaseTimes::record_phase_items(WeakProcessorPhase phase, size_t num_dead, size_t num_total) {
|
||||
uint p = phase_index(phase);
|
||||
assert(!is_initialized_items(_phase_dead_items[p]),
|
||||
"Already set dead items for phase %u", p);
|
||||
assert(!is_initialized_items(_phase_total_items[p]),
|
||||
"Already set total items for phase %u", p);
|
||||
_phase_dead_items[p] = num_dead;
|
||||
_phase_total_items[p] = num_total;
|
||||
}
|
||||
|
||||
WorkerDataArray<double>* WeakProcessorPhaseTimes::worker_data(WeakProcessorPhase phase) const {
|
||||
assert_oop_storage_phase(phase);
|
||||
assert(active_workers() > 1, "No worker data when single-threaded");
|
||||
return _worker_phase_times_sec[WeakProcessorPhases::oop_storage_index(phase)];
|
||||
return _worker_data[WeakProcessorPhases::oop_storage_index(phase)];
|
||||
}
|
||||
|
||||
double WeakProcessorPhaseTimes::worker_time_sec(uint worker_id, WeakProcessorPhase phase) const {
|
||||
@ -155,6 +183,18 @@ void WeakProcessorPhaseTimes::record_worker_time_sec(uint worker_id,
|
||||
}
|
||||
}
|
||||
|
||||
void WeakProcessorPhaseTimes::record_worker_items(uint worker_id,
|
||||
WeakProcessorPhase phase,
|
||||
size_t num_dead,
|
||||
size_t num_total) {
|
||||
if (active_workers() == 1) {
|
||||
record_phase_items(phase, num_dead, num_total);
|
||||
} else {
|
||||
worker_data(phase)->set_or_add_thread_work_item(worker_id, num_dead, DeadItems);
|
||||
worker_data(phase)->set_or_add_thread_work_item(worker_id, num_total, TotalItems);
|
||||
}
|
||||
}
|
||||
|
||||
static double elapsed_time_sec(Ticks start_time, Ticks end_time) {
|
||||
return (end_time - start_time).seconds();
|
||||
}
|
||||
@ -223,6 +263,16 @@ void WeakProcessorPhaseTimes::log_st_phase(WeakProcessorPhase phase,
|
||||
indent_str(indent),
|
||||
WeakProcessorPhases::description(phase),
|
||||
phase_time_sec(phase) * MILLIUNITS);
|
||||
|
||||
log_debug(gc, phases)("%s%s: " SIZE_FORMAT,
|
||||
indent_str(indent + 1),
|
||||
"Dead",
|
||||
_phase_dead_items[phase_index(phase)]);
|
||||
|
||||
log_debug(gc, phases)("%s%s: " SIZE_FORMAT,
|
||||
indent_str(indent + 1),
|
||||
"Total",
|
||||
_phase_total_items[phase_index(phase)]);
|
||||
}
|
||||
|
||||
void WeakProcessorPhaseTimes::log_mt_phase_summary(WeakProcessorPhase phase,
|
||||
@ -231,27 +281,36 @@ void WeakProcessorPhaseTimes::log_mt_phase_summary(WeakProcessorPhase phase,
|
||||
LogStream ls(lt);
|
||||
ls.print("%s", indents[indent]);
|
||||
worker_data(phase)->print_summary_on(&ls, true);
|
||||
log_mt_phase_details(worker_data(phase), indent + 1);
|
||||
|
||||
for (uint i = 0; i < worker_data(phase)->MaxThreadWorkItems; i++) {
|
||||
WorkerDataArray<size_t>* work_items = worker_data(phase)->thread_work_items(i);
|
||||
if (work_items != NULL) {
|
||||
ls.print("%s", indents[indent + 1]);
|
||||
work_items->print_summary_on(&ls, true);
|
||||
log_mt_phase_details(work_items, indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void WeakProcessorPhaseTimes::log_mt_phase_details(WeakProcessorPhase phase,
|
||||
template <typename T>
|
||||
void WeakProcessorPhaseTimes::log_mt_phase_details(WorkerDataArray<T>* data,
|
||||
uint indent) const {
|
||||
LogTarget(Trace, gc, phases) lt;
|
||||
LogStream ls(lt);
|
||||
ls.print("%s", indents[indent]);
|
||||
worker_data(phase)->print_details_on(&ls);
|
||||
if (lt.is_enabled()) {
|
||||
LogStream ls(lt);
|
||||
ls.print("%s", indents[indent]);
|
||||
data->print_details_on(&ls);
|
||||
}
|
||||
}
|
||||
|
||||
void WeakProcessorPhaseTimes::log_print_phases(uint indent) const {
|
||||
if (log_is_enabled(Debug, gc, phases)) {
|
||||
bool details_enabled = log_is_enabled(Trace, gc, phases);
|
||||
FOR_EACH_WEAK_PROCESSOR_PHASE(phase) {
|
||||
if (is_serial_phase(phase) || (active_workers() == 1)) {
|
||||
log_st_phase(phase, indent);
|
||||
} else {
|
||||
log_mt_phase_summary(phase, indent);
|
||||
if (details_enabled) {
|
||||
log_mt_phase_details(phase, indent + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -33,6 +33,10 @@
|
||||
template<typename T> class WorkerDataArray;
|
||||
|
||||
class WeakProcessorPhaseTimes : public CHeapObj<mtGC> {
|
||||
enum {
|
||||
DeadItems,
|
||||
TotalItems
|
||||
};
|
||||
uint _max_threads;
|
||||
uint _active_workers;
|
||||
|
||||
@ -43,15 +47,20 @@ class WeakProcessorPhaseTimes : public CHeapObj<mtGC> {
|
||||
// processed by multiple threads are unused, as are entries for
|
||||
// unexecuted phases.
|
||||
double _phase_times_sec[WeakProcessorPhases::phase_count];
|
||||
size_t _phase_dead_items[WeakProcessorPhases::phase_count];
|
||||
size_t _phase_total_items[WeakProcessorPhases::phase_count];
|
||||
|
||||
// Per-worker times, if multiple threads used and the phase was executed.
|
||||
WorkerDataArray<double>* _worker_phase_times_sec[WeakProcessorPhases::oop_storage_phase_count];
|
||||
// Per-worker times and linked items, if multiple threads used and the phase was executed.
|
||||
WorkerDataArray<double>* _worker_data[WeakProcessorPhases::oop_storage_phase_count];
|
||||
WorkerDataArray<size_t>* _worker_dead_items[WeakProcessorPhases::oop_storage_phase_count];
|
||||
WorkerDataArray<size_t>* _worker_total_items[WeakProcessorPhases::oop_storage_phase_count];
|
||||
|
||||
WorkerDataArray<double>* worker_data(WeakProcessorPhase phase) const;
|
||||
|
||||
void log_st_phase(WeakProcessorPhase phase, uint indent) const;
|
||||
void log_mt_phase_summary(WeakProcessorPhase phase, uint indent) const;
|
||||
void log_mt_phase_details(WeakProcessorPhase phase, uint indent) const;
|
||||
template <typename T>
|
||||
void log_mt_phase_details(WorkerDataArray<T>* data, uint indent) const;
|
||||
|
||||
public:
|
||||
WeakProcessorPhaseTimes(uint max_threads);
|
||||
@ -67,7 +76,9 @@ public:
|
||||
|
||||
void record_total_time_sec(double time_sec);
|
||||
void record_phase_time_sec(WeakProcessorPhase phase, double time_sec);
|
||||
void record_phase_items(WeakProcessorPhase phase, size_t num_dead, size_t num_total);
|
||||
void record_worker_time_sec(uint worker_id, WeakProcessorPhase phase, double time_sec);
|
||||
void record_worker_items(uint worker_id, WeakProcessorPhase phase, size_t num_dead, size_t num_total);
|
||||
|
||||
void reset();
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -23,6 +23,7 @@
|
||||
*/
|
||||
|
||||
#include "precompiled.hpp"
|
||||
#include "classfile/stringTable.hpp"
|
||||
#include "classfile/systemDictionary.hpp"
|
||||
#include "gc/shared/weakProcessorPhases.hpp"
|
||||
#include "runtime/jniHandles.hpp"
|
||||
@ -78,6 +79,7 @@ const char* WeakProcessorPhases::description(Phase phase) {
|
||||
JVMTI_ONLY(case jvmti: return "JVMTI weak processing";)
|
||||
JFR_ONLY(case jfr: return "JFR weak processing";)
|
||||
case jni: return "JNI weak processing";
|
||||
case stringtable: return "StringTable weak processing";
|
||||
case vm: return "VM weak processing";
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
@ -98,9 +100,14 @@ WeakProcessorPhases::Processor WeakProcessorPhases::processor(Phase phase) {
|
||||
OopStorage* WeakProcessorPhases::oop_storage(Phase phase) {
|
||||
switch (phase) {
|
||||
case jni: return JNIHandles::weak_global_handles();
|
||||
case stringtable: return StringTable::weak_storage();
|
||||
case vm: return SystemDictionary::vm_weak_oop_storage();
|
||||
default:
|
||||
ShouldNotReachHere();
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
bool WeakProcessorPhases::is_stringtable(Phase phase) {
|
||||
return phase == stringtable;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -44,6 +44,7 @@ public:
|
||||
|
||||
// OopStorage phases.
|
||||
jni,
|
||||
stringtable,
|
||||
vm
|
||||
};
|
||||
|
||||
@ -65,6 +66,8 @@ public:
|
||||
static const char* description(Phase phase);
|
||||
static Processor processor(Phase phase); // Precondition: is_serial(phase)
|
||||
static OopStorage* oop_storage(Phase phase); // Precondition: is_oop_storage(phase)
|
||||
|
||||
static bool is_stringtable(Phase phase);
|
||||
};
|
||||
|
||||
typedef WeakProcessorPhases::Phase WeakProcessorPhase;
|
||||
|
@ -1923,8 +1923,7 @@ void ShenandoahHeap::unload_classes_and_cleanup_tables(bool full_gc) {
|
||||
ShenandoahPhaseTimings::full_gc_purge_par :
|
||||
ShenandoahPhaseTimings::purge_par);
|
||||
uint active = _workers->active_workers();
|
||||
StringDedupUnlinkOrOopsDoClosure dedup_cl(is_alive, NULL);
|
||||
ParallelCleaningTask unlink_task(is_alive, &dedup_cl, active, purged_class);
|
||||
ParallelCleaningTask unlink_task(is_alive, active, purged_class, true);
|
||||
_workers->run_task(&unlink_task);
|
||||
}
|
||||
|
||||
|
@ -78,7 +78,6 @@ void ShenandoahRootProcessor::process_all_roots_slow(OopClosure* oops) {
|
||||
WeakProcessor::oops_do(oops);
|
||||
ObjectSynchronizer::oops_do(oops);
|
||||
SystemDictionary::oops_do(oops);
|
||||
StringTable::oops_do(oops);
|
||||
|
||||
if (ShenandoahStringDedup::is_enabled()) {
|
||||
ShenandoahStringDedup::oops_do_slow(oops);
|
||||
@ -209,13 +208,6 @@ void ShenandoahRootProcessor::process_vm_roots(OopClosure* strong_roots,
|
||||
ObjectSynchronizer::oops_do(strong_roots);
|
||||
}
|
||||
}
|
||||
|
||||
// All threads execute the following. A specific chunk of buckets
|
||||
// from the StringTable are the individual tasks.
|
||||
if (weak_roots != NULL) {
|
||||
ShenandoahWorkerTimingsTracker timer(worker_times, ShenandoahPhaseTimings::StringTableRoots, worker_id);
|
||||
StringTable::possibly_parallel_oops_do(&_par_state_string, weak_roots);
|
||||
}
|
||||
}
|
||||
|
||||
uint ShenandoahRootProcessor::n_workers() const {
|
||||
|
@ -79,7 +79,6 @@ DEBUG_ONLY(size_t Test_log_prefix_prefixer(char* buf, size_t len);)
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, ref, start)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, reloc)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, start)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, stringtable)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, symboltable)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, sweep)) \
|
||||
LOG_PREFIX(GCId::print_prefix, LOG_TAGS(gc, task)) \
|
||||
|
@ -108,7 +108,6 @@ public class TestGCLogMessages {
|
||||
new LogMessageWithLevel("Skipped Cards", Level.DEBUG),
|
||||
// Ext Root Scan
|
||||
new LogMessageWithLevel("Thread Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("StringTable Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("Universe Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("JNI Handles Roots", Level.TRACE),
|
||||
new LogMessageWithLevel("ObjectSynchronizer Roots", Level.TRACE),
|
||||
@ -126,7 +125,9 @@ public class TestGCLogMessages {
|
||||
new LogMessageWithLevel("Redirtied Cards", Level.TRACE),
|
||||
// Misc Top-level
|
||||
new LogMessageWithLevel("Code Roots Purge", Level.DEBUG),
|
||||
new LogMessageWithLevel("String Dedup Fixup", Level.DEBUG),
|
||||
new LogMessageWithLevel("String Deduplication", Level.DEBUG),
|
||||
new LogMessageWithLevel("Queue Fixup", Level.DEBUG),
|
||||
new LogMessageWithLevel("Table Fixup", Level.DEBUG),
|
||||
new LogMessageWithLevel("Expand Heap After Collection", Level.DEBUG),
|
||||
// Free CSet
|
||||
new LogMessageWithLevel("Free Collection Set", Level.DEBUG),
|
||||
@ -145,6 +146,9 @@ public class TestGCLogMessages {
|
||||
new LogMessageWithLevel("Reference Processing", Level.DEBUG),
|
||||
// VM internal reference processing
|
||||
new LogMessageWithLevel("Weak Processing", Level.DEBUG),
|
||||
new LogMessageWithLevel("JNI weak processing", Level.DEBUG),
|
||||
new LogMessageWithLevel("StringTable weak processing", Level.DEBUG),
|
||||
new LogMessageWithLevel("VM weak processing", Level.DEBUG),
|
||||
|
||||
new LogMessageWithLevelC2OrJVMCIOnly("DerivedPointerTable Update", Level.DEBUG),
|
||||
new LogMessageWithLevel("Start New Collection Set", Level.DEBUG),
|
||||
|
@ -1,63 +0,0 @@
|
||||
/*
|
||||
* Copyright (c) 2013, 2019, 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.
|
||||
*/
|
||||
|
||||
package gc.g1;
|
||||
|
||||
/*
|
||||
* @test TestStringTableStats
|
||||
* @bug 8027476 8027455
|
||||
* @summary Ensure that the G1TraceStringTableScrubbing prints the expected message.
|
||||
* @key gc
|
||||
* @requires vm.gc.G1
|
||||
* @library /test/lib
|
||||
* @modules java.base/jdk.internal.misc
|
||||
* java.management
|
||||
* @run main gc.g1.TestStringTableStats
|
||||
*/
|
||||
|
||||
import jdk.test.lib.process.OutputAnalyzer;
|
||||
import jdk.test.lib.process.ProcessTools;
|
||||
|
||||
public class TestStringTableStats {
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder("-XX:+UseG1GC",
|
||||
"-XX:+UnlockExperimentalVMOptions",
|
||||
"-Xlog:gc+stringtable=trace",
|
||||
SystemGCTest.class.getName());
|
||||
|
||||
OutputAnalyzer output = new OutputAnalyzer(pb.start());
|
||||
|
||||
System.out.println("Output:\n" + output.getOutput());
|
||||
|
||||
output.shouldMatch("GC\\(\\d+\\) Cleaned string table");
|
||||
output.shouldHaveExitValue(0);
|
||||
}
|
||||
|
||||
static class SystemGCTest {
|
||||
public static void main(String [] args) {
|
||||
System.out.println("Calling System.gc()");
|
||||
System.gc();
|
||||
}
|
||||
}
|
||||
}
|
@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
|
||||
* Copyright (c) 2018, 2019, 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
|
||||
@ -90,7 +90,6 @@ public class TestG1ParallelPhases {
|
||||
Set<String> allPhases = of(
|
||||
"ExtRootScan",
|
||||
"ThreadRoots",
|
||||
"StringTableRoots",
|
||||
"UniverseRoots",
|
||||
"JNIRoots",
|
||||
"ObjectSynchronizerRoots",
|
||||
|
Loading…
x
Reference in New Issue
Block a user