8213229: Investigate treating StringTable as weak in young collections

Reviewed-by: zgu, kbarrett
This commit is contained in:
Thomas Schatzl 2019-01-29 11:30:17 +01:00
parent 51e2252a73
commit d800361151
42 changed files with 319 additions and 555 deletions

@ -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",