提交 bca48990 编写于 作者: S stefank

8048269: Add flag to turn off class unloading after G1 concurrent mark

Summary: Added -XX:+/-ClassUnloadingWithConcurrentMark
Reviewed-by: jmasa, brutisso, mgerdin
上级 a506f1d6
...@@ -2157,7 +2157,9 @@ void ConcurrentMark::cleanup() { ...@@ -2157,7 +2157,9 @@ void ConcurrentMark::cleanup() {
g1h->increment_total_collections(); g1h->increment_total_collections();
// Clean out dead classes and update Metaspace sizes. // Clean out dead classes and update Metaspace sizes.
ClassLoaderDataGraph::purge(); if (ClassUnloadingWithConcurrentMark) {
ClassLoaderDataGraph::purge();
}
MetaspaceGC::compute_new_size(); MetaspaceGC::compute_new_size();
// We reclaimed old regions so we should calculate the sizes to make // We reclaimed old regions so we should calculate the sizes to make
...@@ -2585,24 +2587,27 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) { ...@@ -2585,24 +2587,27 @@ void ConcurrentMark::weakRefsWork(bool clear_all_soft_refs) {
assert(_markStack.isEmpty(), "Marking should have completed"); assert(_markStack.isEmpty(), "Marking should have completed");
// Unload Klasses, String, Symbols, Code Cache, etc. // Unload Klasses, String, Symbols, Code Cache, etc.
{
G1RemarkGCTraceTime trace("Unloading", G1Log::finer());
G1RemarkGCTraceTime trace("Unloading", G1Log::finer()); if (ClassUnloadingWithConcurrentMark) {
bool purged_classes;
bool purged_classes;
{ {
G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest()); G1RemarkGCTraceTime trace("System Dictionary Unloading", G1Log::finest());
purged_classes = SystemDictionary::do_unloading(&g1_is_alive); purged_classes = SystemDictionary::do_unloading(&g1_is_alive);
} }
{ {
G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest()); G1RemarkGCTraceTime trace("Parallel Unloading", G1Log::finest());
weakRefsWorkParallelPart(&g1_is_alive, purged_classes); weakRefsWorkParallelPart(&g1_is_alive, purged_classes);
} }
}
if (G1StringDedup::is_enabled()) { if (G1StringDedup::is_enabled()) {
G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest()); G1RemarkGCTraceTime trace("String Deduplication Unlink", G1Log::finest());
G1StringDedup::unlink(&g1_is_alive); G1StringDedup::unlink(&g1_is_alive);
}
} }
} }
......
...@@ -4860,10 +4860,15 @@ public: ...@@ -4860,10 +4860,15 @@ public:
if (_g1h->g1_policy()->during_initial_mark_pause()) { if (_g1h->g1_policy()->during_initial_mark_pause()) {
// We also need to mark copied objects. // We also need to mark copied objects.
strong_root_cl = &scan_mark_root_cl; strong_root_cl = &scan_mark_root_cl;
weak_root_cl = &scan_mark_weak_root_cl;
strong_cld_cl = &scan_mark_cld_cl; strong_cld_cl = &scan_mark_cld_cl;
weak_cld_cl = &scan_mark_weak_cld_cl;
strong_code_cl = &scan_mark_code_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 { } else {
strong_root_cl = &scan_only_root_cl; strong_root_cl = &scan_only_root_cl;
weak_root_cl = &scan_only_root_cl; weak_root_cl = &scan_only_root_cl;
...@@ -4934,6 +4939,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots, ...@@ -4934,6 +4939,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
double closure_app_time_sec = 0.0; double closure_app_time_sec = 0.0;
bool during_im = _g1h->g1_policy()->during_initial_mark_pause(); 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_roots(scan_non_heap_roots);
BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots); BufferingOopClosure buf_scan_non_heap_weak_roots(scan_non_heap_weak_roots);
...@@ -4943,8 +4949,8 @@ g1_process_roots(OopClosure* scan_non_heap_roots, ...@@ -4943,8 +4949,8 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
&buf_scan_non_heap_roots, &buf_scan_non_heap_roots,
&buf_scan_non_heap_weak_roots, &buf_scan_non_heap_weak_roots,
scan_strong_clds, scan_strong_clds,
// Initial Mark handles the weak CLDs separately. // Unloading Initial Marks handle the weak CLDs separately.
(during_im ? NULL : scan_weak_clds), (trace_metadata ? NULL : scan_weak_clds),
scan_strong_code); scan_strong_code);
// Now the CM ref_processor roots. // Now the CM ref_processor roots.
...@@ -4956,7 +4962,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots, ...@@ -4956,7 +4962,7 @@ g1_process_roots(OopClosure* scan_non_heap_roots,
ref_processor_cm()->weak_oops_do(&buf_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 // Barrier to make sure all workers passed
// the strong CLD and strong nmethods phases. // the strong CLD and strong nmethods phases.
active_strong_roots_scope()->wait_until_all_workers_done_with_threads(n_par_threads()); 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 { ...@@ -94,26 +94,37 @@ G1OffsetTableContigSpace::block_start_const(const void* p) const {
inline bool inline bool
HeapRegion::block_is_obj(const HeapWord* p) const { HeapRegion::block_is_obj(const HeapWord* p) const {
G1CollectedHeap* g1h = G1CollectedHeap::heap(); 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 inline size_t
HeapRegion::block_size(const HeapWord *addr) const { 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 // Old regions' dead objects may have dead classes
// We need to find the next live object in some other // We need to find the next live object in some other
// manner than getting the oop size // manner than getting the oop size
G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
if (g1h->is_obj_dead(oop(addr), this)) { HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()->
HeapWord* next = g1h->concurrent_mark()->prevMarkBitMap()-> getNextMarkedWordAddress(addr, prev_top_at_mark_start());
getNextMarkedWordAddress(addr, prev_top_at_mark_start());
assert(next > addr, "must get the next live object");
return pointer_delta(next, addr); assert(next > addr, "must get the next live object");
} else if (addr == top()) { return pointer_delta(next, addr);
return pointer_delta(end(), addr);
}
return oop(addr)->size();
} }
inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t word_size) { inline HeapWord* HeapRegion::par_allocate_no_bot_updates(size_t word_size) {
......
...@@ -209,6 +209,7 @@ void VM_GenCollectFull::doit() { ...@@ -209,6 +209,7 @@ void VM_GenCollectFull::doit() {
gch->do_full_collection(gch->must_clear_all_soft_refs(), _max_level); 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() { bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() {
#if INCLUDE_ALL_GCS #if INCLUDE_ALL_GCS
if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) { if (UseConcMarkSweepGC && CMSClassUnloadingEnabled) {
...@@ -216,7 +217,7 @@ bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() { ...@@ -216,7 +217,7 @@ bool VM_CollectForMetadataAllocation::initiate_concurrent_GC() {
return true; return true;
} }
if (UseG1GC) { if (UseG1GC && ClassUnloadingWithConcurrentMark) {
G1CollectedHeap* g1h = G1CollectedHeap::heap(); G1CollectedHeap* g1h = G1CollectedHeap::heap();
g1h->g1_policy()->set_initiate_conc_mark_if_possible(); g1h->g1_policy()->set_initiate_conc_mark_if_possible();
......
...@@ -159,9 +159,9 @@ SharedHeap::StrongRootsScope::~StrongRootsScope() { ...@@ -159,9 +159,9 @@ SharedHeap::StrongRootsScope::~StrongRootsScope() {
Monitor* SharedHeap::StrongRootsScope::_lock = new Monitor(Mutex::leaf, "StrongRootsScope lock", false); Monitor* SharedHeap::StrongRootsScope::_lock = new Monitor(Mutex::leaf, "StrongRootsScope lock", false);
void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) { 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. // 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); uint new_value = (uint)Atomic::add(1, &_n_workers_done_with_threads);
if (new_value == n_workers) { if (new_value == n_workers) {
// This thread is last. Notify the others. // This thread is last. Notify the others.
...@@ -172,6 +172,9 @@ void SharedHeap::StrongRootsScope::mark_worker_done_with_threads(uint n_workers) ...@@ -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) { 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. // No need to use the barrier if this is single-threaded code.
if (n_workers > 0 && (uint)_n_workers_done_with_threads != n_workers) { if (n_workers > 0 && (uint)_n_workers_done_with_threads != n_workers) {
MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag); MonitorLockerEx ml(_lock, Mutex::_no_safepoint_check_flag);
......
...@@ -1064,6 +1064,9 @@ class CommandLineFlags { ...@@ -1064,6 +1064,9 @@ class CommandLineFlags {
product(bool, ClassUnloading, true, \ product(bool, ClassUnloading, true, \
"Do unloading of classes") \ "Do unloading of classes") \
\ \
product(bool, ClassUnloadingWithConcurrentMark, true, \
"Do unloading of classes with a concurrent marking cycle") \
\
develop(bool, DisableStartThread, false, \ develop(bool, DisableStartThread, false, \
"Disable starting of additional Java threads " \ "Disable starting of additional Java threads " \
"(for debugging only)") \ "(for debugging only)") \
......
...@@ -170,6 +170,7 @@ compact1 = \ ...@@ -170,6 +170,7 @@ compact1 = \
needs_full_vm_compact1 = \ needs_full_vm_compact1 = \
runtime/NMT \ runtime/NMT \
gc/class_unloading/TestCMSClassUnloadingDisabledHWM.java \ gc/class_unloading/TestCMSClassUnloadingDisabledHWM.java \
gc/class_unloading/TestG1ClassUnloadingHWM.java \
gc/g1/TestRegionAlignment.java \ gc/g1/TestRegionAlignment.java \
gc/g1/TestShrinkToOneRegion.java \ gc/g1/TestShrinkToOneRegion.java \
gc/metaspace/G1AddMetaspaceDependency.java \ gc/metaspace/G1AddMetaspaceDependency.java \
......
...@@ -21,54 +21,8 @@ ...@@ -21,54 +21,8 @@
* questions. * 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 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 { class AllocateBeyondMetaspaceSize {
public static Object dummy; public static Object dummy;
......
/*
* 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();
}
}
/*
* 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();
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册