8048269: Add flag to turn off class unloading after G1 concurrent mark
Added -XX:+/-ClassUnloadingWithConcurrentMark Reviewed-by: jmasa, brutisso, mgerdin
This commit is contained in:
parent
bdeaedbd38
commit
ef47f5dc0e
hotspot
src/share/vm
gc_implementation
memory
runtime
test
@ -2167,7 +2167,9 @@ void ConcurrentMark::cleanup() {
|
||||
g1h->increment_total_collections();
|
||||
|
||||
// Clean out dead classes and update Metaspace sizes.
|
||||
ClassLoaderDataGraph::purge();
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
ClassLoaderDataGraph::purge();
|
||||
}
|
||||
MetaspaceGC::compute_new_size();
|
||||
|
||||
// We reclaimed old regions so we should calculate the sizes to make
|
||||
@ -2597,24 +2599,27 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
|
||||
assert(_markStack.isEmpty(), "Marking should have completed");
|
||||
|
||||
// Unload Klasses, String, Symbols, Code Cache, etc.
|
||||
|
||||
G1RemarkGCTraceTime trace("Unloading", G1Log::finer());
|
||||
|
||||
bool purged_classes;
|
||||
|
||||
{
|
||||
G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest());
|
||||
purged_classes = SystemDictionary::do_unloading(&g1_is_alive);
|
||||
}
|
||||
G1RemarkGCTraceTime trace("Unloading", G1Log::finer());
|
||||
|
||||
{
|
||||
G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest());
|
||||
weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
|
||||
}
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
bool purged_classes;
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest());
|
||||
G1StringDedup::unlink(&g1_is_alive);
|
||||
{
|
||||
G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest());
|
||||
purged_classes = SystemDictionary::do_unloading(&g1_is_alive);
|
||||
}
|
||||
|
||||
{
|
||||
G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest());
|
||||
weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
|
||||
}
|
||||
}
|
||||
|
||||
if (G1StringDedup::is_enabled()) {
|
||||
G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest());
|
||||
G1StringDedup::unlink(&g1_is_alive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4920,10 +4920,15 @@ public:
|
||||
if (_g1h->g1_policy()->during_initial_mark_pause()) {
|
||||
// We also need to mark copied objects.
|
||||
strong_root_cl = &scan_mark_root_cl;
|
||||
weak_root_cl = &scan_mark_weak_root_cl;
|
||||
strong_cld_cl = &scan_mark_cld_cl;
|
||||
weak_cld_cl = &scan_mark_weak_cld_cl;
|
||||
strong_code_cl = &scan_mark_code_cl;
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
weak_root_cl = &scan_mark_weak_root_cl;
|
||||
weak_cld_cl = &scan_mark_weak_cld_cl;
|
||||
} else {
|
||||
weak_root_cl = &scan_mark_root_cl;
|
||||
weak_cld_cl = &scan_mark_cld_cl;
|
||||
}
|
||||
} else {
|
||||
strong_root_cl = &scan_only_root_cl;
|
||||
weak_root_cl = &scan_only_root_cl;
|
||||
@ -4994,6 +4999,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
|
||||
double closure_app_time_sec = 0.0;
|
||||
|
||||
bool during_im = _g1h->g1_policy()->during_initial_mark_pause();
|
||||
bool trace_metadata = during_im && ClassUnloadingWithConcurrentMark;
|
||||
|
||||
BufferingOopClosure buf_scan_non_heap_roots(scan_non_heap_roots);
|
||||
BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots);
|
||||
@ -5003,8 +5009,8 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
|
||||
&buf_scan_non_heap_roots,
|
||||
&buf_scan_non_heap_weak_roots,
|
||||
scan_strong_clds,
|
||||
// Initial Mark handles the weak CLDs separately.
|
||||
(during_im ? NULL : scan_weak_clds),
|
||||
// Unloading Initial Marks handle the weak CLDs separately.
|
||||
(trace_metadata ? NULL : scan_weak_clds),
|
||||
scan_strong_code);
|
||||
|
||||
// Now the CM ref_processor roots.
|
||||
@ -5016,7 +5022,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
|
||||
ref_processor_cm()->weak_oops_do(&buf_scan_non_heap_roots);
|
||||
}
|
||||
|
||||
if (during_im) {
|
||||
if (trace_metadata) {
|
||||
// Barrier to make sure all workers passed
|
||||
// the strong CLD and strong nmethods phases.
|
||||
active_strong_roots_scope()->wait_until_all_workers_done_with_threads(n_par_threads());
|
||||
|
@ -94,26 +94,37 @@ G1OffsetTableContigSpace::block_start_const(const void* p) const {
|
||||
inline bool
|
||||
HeapRegion::block_is_obj(const HeapWord* p) const {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
return !g1h->is_obj_dead(oop(p), this);
|
||||
if (ClassUnloadingWithConcurrentMark) {
|
||||
return !g1h->is_obj_dead(oop(p), this);
|
||||
}
|
||||
return p < top();
|
||||
}
|
||||
|
||||
inline size_t
|
||||
HeapRegion::block_size(const HeapWord *addr) const {
|
||||
if (addr == top()) {
|
||||
return pointer_delta(end(), addr);
|
||||
}
|
||||
|
||||
if (block_is_obj(addr)) {
|
||||
return oop(addr)->size();
|
||||
}
|
||||
|
||||
assert(ClassUnloadingWithConcurrentMark,
|
||||
err_msg("All blocks should be objects if G1 Class Unloading isn't used. "
|
||||
"HR: ["PTR_FORMAT", "PTR_FORMAT", "PTR_FORMAT") "
|
||||
"addr: " PTR_FORMAT,
|
||||
p2i(bottom()), p2i(top()), p2i(end()), p2i(addr)));
|
||||
|
||||
// Old regions' dead objects may have dead classes
|
||||
// We need to find the next live object in some other
|
||||
// manner than getting the oop size
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
if (g1h->is_obj_dead(oop(addr), this)) {
|
||||
HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()->
|
||||
getNextMarkedWordAddress(addr, prev_top_at_mark_start());
|
||||
HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()->
|
||||
getNextMarkedWordAddress(addr, prev_top_at_mark_start());
|
||||
|
||||
assert(next > addr, "must get the next live object");
|
||||
|
||||
return pointer_delta(next, addr);
|
||||
} else if (addr == top()) {
|
||||
return pointer_delta(end(), addr);
|
||||
}
|
||||
return oop(addr)->size();
|
||||
assert(next > addr, "must get the next live object");
|
||||
return pointer_delta(next, addr);
|
||||
}
|
||||
|
||||
inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t word_size) {
|
||||
|
@ -195,6 +195,7 @@ void VM_GenCollectFull::doit() {
|
||||
gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level);
|
||||
}
|
||||
|
||||
// Returns true iff concurrent GCs unloads metadata.
|
||||
bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() {
|
||||
#if INCLUDE_ALL_GCS
|
||||
if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) {
|
||||
@ -202,7 +203,7 @@ bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (UseG1GC) {
|
||||
if (UseG1GC && ClassUnloadingWithConcurrentMark) {
|
||||
G1CollectedHeap* g1h = G1CollectedHeap::heap();
|
||||
g1h->g1_policy()->set_initiate_conc_mark_if_possible();
|
||||
|
||||
|
@ -159,9 +159,9 @@ SharedHeap::StrongRootsScope::~StrongRootsScope() {
|
||||
Monitor* SharedHeap::StrongRootsScope::_lock = new Monitor(Mutex::leaf, "StrongRootsScope lock", false);
|
||||
|
||||
void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) {
|
||||
// The Thread work barrier is only needed by G1.
|
||||
// The Thread work barrier is only needed by G1 Class Unloading.
|
||||
// No need to use the barrier if this is single-threaded code.
|
||||
if (UseG1GC && n_workers > 0) {
|
||||
if (UseG1GC && ClassUnloadingWithConcurrentMark && n_workers > 0) {
|
||||
uint new_value = (uint)Atomic::add(1, &_n_workers_done_with_threads);
|
||||
if (new_value == n_workers) {
|
||||
// This thread is last. Notify the others.
|
||||
@ -172,6 +172,9 @@ void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers)
|
||||
}
|
||||
|
||||
void SharedHeap::StrongRootsScope::wait_until_all_workers_done_with_threads(uint n_workers) {
|
||||
assert(UseG1GC, "Currently only used by G1");
|
||||
assert(ClassUnloadingWithConcurrentMark, "Currently only needed when doing G1 Class Unloading");
|
||||
|
||||
// No need to use the barrier if this is single-threaded code.
|
||||
if (n_workers > 0 && (uint)_n_workers_done_with_threads != n_workers) {
|
||||
MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
|
||||
|
@ -1078,6 +1078,9 @@ class CommandLineFlags {
|
||||
product(bool, ClassUnloading, true, \
|
||||
"Do unloading of classes") \
|
||||
\
|
||||
product(bool, ClassUnloadingWithConcurrentMark, true, \
|
||||
"Do unloading of classes with a concurrent marking cycle") \
|
||||
\
|
||||
develop(bool, DisableStartThread, false, \
|
||||
"Disable starting of additional Java threads " \
|
||||
"(for debugging only)") \
|
||||
|
@ -217,6 +217,7 @@ needs_g1gc = \
|
||||
gc/arguments/TestMaxHeapSizeTools.java \
|
||||
gc/arguments/TestMaxNewSize.java \
|
||||
gc/arguments/TestUseCompressedOopsErgo.java \
|
||||
gc/class_unloading/TestG1ClassUnloadingHWM.java \
|
||||
gc/g1/ \
|
||||
gc/metaspace/G1AddMetaspaceDependency.java \
|
||||
gc/metaspace/TestMetaspacePerfCounters.java \
|
||||
@ -257,7 +258,7 @@ needs_cmsgc = \
|
||||
gc/arguments/TestCMSHeapSizeFlags.java \
|
||||
gc/arguments/TestMaxNewSize.java \
|
||||
gc/arguments/TestUseCompressedOopsErgo.java \
|
||||
gc/class_unloading/TestCMSClassUnloadingDisabledHWM.java \
|
||||
gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java \
|
||||
gc/concurrentMarkSweep/ \
|
||||
gc/startup_warnings/TestCMS.java \
|
||||
gc/startup_warnings/TestCMSIncrementalMode.java \
|
||||
|
@ -21,54 +21,8 @@
|
||||
* questions.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key gc
|
||||
* @bug 8049831
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build TestCMSClassUnloadingDisabledHWM
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run driver TestCMSClassUnloadingDisabledHWM
|
||||
* @summary Test that -XX:-CMSClassUnloadingEnabled will trigger a Full GC when more than MetaspaceSize metadata is allocated.
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
import sun.hotspot.WhiteBox;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TestCMSClassUnloadingDisabledHWM {
|
||||
|
||||
private static OutputAnalyzer run(long metaspaceSize, long youngGenSize) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-Xbootclasspath/a:.",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:MetaspaceSize=" + metaspaceSize,
|
||||
"-Xmn" + youngGenSize,
|
||||
"-XX:+UseConcMarkSweepGC",
|
||||
"-XX:-CMSClassUnloadingEnabled",
|
||||
"-XX:+PrintHeapAtGC",
|
||||
"-XX:+PrintGCDetails",
|
||||
"AllocateBeyondMetaspaceSize",
|
||||
"" + metaspaceSize,
|
||||
"" + youngGenSize);
|
||||
return new OutputAnalyzer(pb.start());
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
long metaspaceSize = 32 * 1024 * 1024;
|
||||
long youngGenSize = 32 * 1024 * 1024;
|
||||
|
||||
OutputAnalyzer out = run(metaspaceSize, youngGenSize);
|
||||
|
||||
// -XX:-CMSClassUnloadingEnabled is used, so we expect a full GC instead of a concurrent cycle.
|
||||
out.shouldMatch(".*Full GC.*");
|
||||
out.shouldNotMatch(".*CMS Initial Mark.*");
|
||||
}
|
||||
}
|
||||
|
||||
class AllocateBeyondMetaspaceSize {
|
||||
public static Object dummy;
|
||||
|
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key gc
|
||||
* @bug 8049831
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build TestCMSClassUnloadingEnabledHWM AllocateBeyondMetaspaceSize
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run driver TestCMSClassUnloadingEnabledHWM
|
||||
* @summary Test that -XX:-CMSClassUnloadingEnabled will trigger a Full GC when more than MetaspaceSize metadata is allocated.
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TestCMSClassUnloadingEnabledHWM {
|
||||
private static long MetaspaceSize = 32 * 1024 * 1024;
|
||||
private static long YoungGenSize = 32 * 1024 * 1024;
|
||||
|
||||
private static OutputAnalyzer run(boolean enableUnloading) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-Xbootclasspath/a:.",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:MetaspaceSize=" + MetaspaceSize,
|
||||
"-Xmn" + YoungGenSize,
|
||||
"-XX:+UseConcMarkSweepGC",
|
||||
"-XX:" + (enableUnloading ? "+" : "-") + "CMSClassUnloadingEnabled",
|
||||
"-XX:+PrintHeapAtGC",
|
||||
"-XX:+PrintGCDetails",
|
||||
"AllocateBeyondMetaspaceSize",
|
||||
"" + MetaspaceSize,
|
||||
"" + YoungGenSize);
|
||||
return new OutputAnalyzer(pb.start());
|
||||
}
|
||||
|
||||
public static OutputAnalyzer runWithCMSClassUnloading() throws Exception {
|
||||
return run(true);
|
||||
}
|
||||
|
||||
public static OutputAnalyzer runWithoutCMSClassUnloading() throws Exception {
|
||||
return run(false);
|
||||
}
|
||||
|
||||
public static void testWithoutCMSClassUnloading() throws Exception {
|
||||
// -XX:-CMSClassUnloadingEnabled is used, so we expect a full GC instead of a concurrent cycle.
|
||||
OutputAnalyzer out = runWithoutCMSClassUnloading();
|
||||
|
||||
out.shouldMatch(".*Full GC.*");
|
||||
out.shouldNotMatch(".*CMS Initial Mark.*");
|
||||
}
|
||||
|
||||
public static void testWithCMSClassUnloading() throws Exception {
|
||||
// -XX:+CMSClassUnloadingEnabled is used, so we expect a concurrent cycle instead of a full GC.
|
||||
OutputAnalyzer out = runWithCMSClassUnloading();
|
||||
|
||||
out.shouldMatch(".*CMS Initial Mark.*");
|
||||
out.shouldNotMatch(".*Full GC.*");
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
testWithCMSClassUnloading();
|
||||
testWithoutCMSClassUnloading();
|
||||
}
|
||||
}
|
||||
|
90
hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java
Normal file
90
hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* Copyright (c) 2014, 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.
|
||||
*/
|
||||
|
||||
/*
|
||||
* @test
|
||||
* @key gc
|
||||
* @bug 8049831
|
||||
* @library /testlibrary /testlibrary/whitebox
|
||||
* @build TestG1ClassUnloadingHWM AllocateBeyondMetaspaceSize
|
||||
* @run main ClassFileInstaller sun.hotspot.WhiteBox
|
||||
* @run driver TestG1ClassUnloadingHWM
|
||||
* @summary Test that -XX:-ClassUnloadingWithConcurrentMark will trigger a Full GC when more than MetaspaceSize metadata is allocated.
|
||||
*/
|
||||
|
||||
import com.oracle.java.testlibrary.OutputAnalyzer;
|
||||
import com.oracle.java.testlibrary.ProcessTools;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
|
||||
public class TestG1ClassUnloadingHWM {
|
||||
private static long MetaspaceSize = 32 * 1024 * 1024;
|
||||
private static long YoungGenSize = 32 * 1024 * 1024;
|
||||
|
||||
private static OutputAnalyzer run(boolean enableUnloading) throws Exception {
|
||||
ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
|
||||
"-Xbootclasspath/a:.",
|
||||
"-XX:+WhiteBoxAPI",
|
||||
"-XX:MetaspaceSize=" + MetaspaceSize,
|
||||
"-Xmn" + YoungGenSize,
|
||||
"-XX:+UseG1GC",
|
||||
"-XX:" + (enableUnloading ? "+" : "-") + "ClassUnloadingWithConcurrentMark",
|
||||
"-XX:+PrintHeapAtGC",
|
||||
"-XX:+PrintGCDetails",
|
||||
"AllocateBeyondMetaspaceSize",
|
||||
"" + MetaspaceSize,
|
||||
"" + YoungGenSize);
|
||||
return new OutputAnalyzer(pb.start());
|
||||
}
|
||||
|
||||
public static OutputAnalyzer runWithG1ClassUnloading() throws Exception {
|
||||
return run(true);
|
||||
}
|
||||
|
||||
public static OutputAnalyzer runWithoutG1ClassUnloading() throws Exception {
|
||||
return run(false);
|
||||
}
|
||||
|
||||
public static void testWithoutG1ClassUnloading() throws Exception {
|
||||
// -XX:-ClassUnloadingWithConcurrentMark is used, so we expect a full GC instead of a concurrent cycle.
|
||||
OutputAnalyzer out = runWithoutG1ClassUnloading();
|
||||
|
||||
out.shouldMatch(".*Full GC.*");
|
||||
out.shouldNotMatch(".*initial-mark.*");
|
||||
}
|
||||
|
||||
public static void testWithG1ClassUnloading() throws Exception {
|
||||
// -XX:+ClassUnloadingWithConcurrentMark is used, so we expect a concurrent cycle instead of a full GC.
|
||||
OutputAnalyzer out = runWithG1ClassUnloading();
|
||||
|
||||
out.shouldMatch(".*initial-mark.*");
|
||||
out.shouldNotMatch(".*Full GC.*");
|
||||
}
|
||||
|
||||
public static void main(String args[]) throws Exception {
|
||||
testWithG1ClassUnloading();
|
||||
testWithoutG1ClassUnloading();
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user