8048269: Add flag to turn off class unloading after G1 concurrent mark
Summary: Added -XX:+/-ClassUnloadingWithConcurrentMark
Reviewed-by: jmasa, brutisso, mgerdin
--- a/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/concurrentMark.cpp Wed Aug 06 09:55:16 2014 +0200
@@ -2167,7 +2167,9 @@
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 @@
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("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);
+ G1RemarkGCTraceTime trace("Unloading", G1Log::finer());
+
+ if (ClassUnloadingWithConcurrentMark) {
+ bool purged_classes;
+
+ {
+ 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);
+ }
}
}
--- a/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/g1CollectedHeap.cpp Wed Aug 06 09:55:16 2014 +0200
@@ -4920,10 +4920,15 @@
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 @@
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 @@
&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 @@
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());
--- a/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/g1/heapRegion.inline.hpp Wed Aug 06 09:55:16 2014 +0200
@@ -94,26 +94,37 @@
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());
-
- assert(next > addr, "must get the next live object");
+ HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()->
+ getNextMarkedWordAddress(addr, prev_top_at_mark_start());
- 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) {
--- a/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/gc_implementation/shared/vmGCOperations.cpp Wed Aug 06 09:55:16 2014 +0200
@@ -195,6 +195,7 @@
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 @@
return true;
}
- if (UseG1GC) {
+ if (UseG1GC && ClassUnloadingWithConcurrentMark) {
G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->g1_policy()->set_initiate_conc_mark_if_possible();
--- a/hotspot/src/share/vm/memory/sharedHeap.cpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/memory/sharedHeap.cpp Wed Aug 06 09:55:16 2014 +0200
@@ -159,9 +159,9 @@
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::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);
--- a/hotspot/src/share/vm/runtime/globals.hpp Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/src/share/vm/runtime/globals.hpp Wed Aug 06 09:55:16 2014 +0200
@@ -1078,6 +1078,9 @@
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)") \
--- a/hotspot/test/TEST.groups Mon Aug 04 15:04:45 2014 +0200
+++ b/hotspot/test/TEST.groups Wed Aug 06 09:55:16 2014 +0200
@@ -217,6 +217,7 @@
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 @@
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 \
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/class_unloading/AllocateBeyondMetaspaceSize.java Wed Aug 06 09:55:16 2014 +0200
@@ -0,0 +1,59 @@
+/*
+ * 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.
+ */
+
+import sun.hotspot.WhiteBox;
+
+class AllocateBeyondMetaspaceSize {
+ public static Object dummy;
+
+ public static void main(String [] args) {
+ if (args.length != 2) {
+ throw new IllegalArgumentException("Usage: <MetaspaceSize> <YoungGenSize>");
+ }
+
+ long metaspaceSize = Long.parseLong(args[0]);
+ long youngGenSize = Long.parseLong(args[1]);
+
+ run(metaspaceSize, youngGenSize);
+ }
+
+ private static void run(long metaspaceSize, long youngGenSize) {
+ WhiteBox wb = WhiteBox.getWhiteBox();
+
+ long allocationBeyondMetaspaceSize = metaspaceSize * 2;
+ long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize);
+
+ triggerYoungGC(youngGenSize);
+
+ wb.freeMetaspace(null, metaspace, metaspace);
+ }
+
+ private static void triggerYoungGC(long youngGenSize) {
+ long approxAllocSize = 32 * 1024;
+ long numAllocations = 2 * youngGenSize / approxAllocSize;
+
+ for (long i = 0; i < numAllocations; i++) {
+ dummy = new byte[(int)approxAllocSize];
+ }
+ }
+}
--- a/hotspot/test/gc/class_unloading/TestCMSClassUnloadingDisabledHWM.java Mon Aug 04 15:04:45 2014 +0200
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,105 +0,0 @@
-/*
- * 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 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;
-
- public static void main(String [] args) {
- if (args.length != 2) {
- throw new IllegalArgumentException("Usage: <MetaspaceSize> <YoungGenSize>");
- }
-
- long metaspaceSize = Long.parseLong(args[0]);
- long youngGenSize = Long.parseLong(args[1]);
-
- run(metaspaceSize, youngGenSize);
- }
-
- private static void run(long metaspaceSize, long youngGenSize) {
- WhiteBox wb = WhiteBox.getWhiteBox();
-
- long allocationBeyondMetaspaceSize = metaspaceSize * 2;
- long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize);
-
- triggerYoungGC(youngGenSize);
-
- wb.freeMetaspace(null, metaspace, metaspace);
- }
-
- private static void triggerYoungGC(long youngGenSize) {
- long approxAllocSize = 32 * 1024;
- long numAllocations = 2 * youngGenSize / approxAllocSize;
-
- for (long i = 0; i < numAllocations; i++) {
- dummy = new byte[(int)approxAllocSize];
- }
- }
-}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/class_unloading/TestCMSClassUnloadingEnabledHWM.java Wed Aug 06 09:55:16 2014 +0200
@@ -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();
+ }
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hotspot/test/gc/class_unloading/TestG1ClassUnloadingHWM.java Wed Aug 06 09:55:16 2014 +0200
@@ -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();
+ }
+}
+