Fri, 20 Jul 2018 03:07:49 -0400
8114823: G1 doesn't honor request to disable class unloading
Reviewed-by: tschatzl
1.1 --- a/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Tue Jul 17 17:07:44 2018 +0200 1.2 +++ b/src/share/vm/gc_implementation/g1/g1MarkSweep.cpp Fri Jul 20 03:07:49 2018 -0400 1.3 @@ -1,5 +1,5 @@ 1.4 /* 1.5 - * Copyright (c) 2001, 2014, Oracle and/or its affiliates. All rights reserved. 1.6 + * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved. 1.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 1.8 * 1.9 * This code is free software; you can redistribute it and/or modify it 1.10 @@ -135,9 +135,16 @@ 1.11 MarkingCodeBlobClosure follow_code_closure(&GenMarkSweep::follow_root_closure, !CodeBlobToOopClosure::FixRelocations); 1.12 { 1.13 G1RootProcessor root_processor(g1h); 1.14 - root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure, 1.15 - &GenMarkSweep::follow_cld_closure, 1.16 - &follow_code_closure); 1.17 + if (ClassUnloading) { 1.18 + root_processor.process_strong_roots(&GenMarkSweep::follow_root_closure, 1.19 + &GenMarkSweep::follow_cld_closure, 1.20 + &follow_code_closure); 1.21 + } else { 1.22 + root_processor.process_all_roots_no_string_table( 1.23 + &GenMarkSweep::follow_root_closure, 1.24 + &GenMarkSweep::follow_cld_closure, 1.25 + &follow_code_closure); 1.26 + } 1.27 } 1.28 1.29 // Process reference objects found during marking 1.30 @@ -158,15 +165,17 @@ 1.31 // This is the point where the entire marking should have completed. 1.32 assert(GenMarkSweep::_marking_stack.is_empty(), "Marking should have completed"); 1.33 1.34 - // Unload classes and purge the SystemDictionary. 1.35 - bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); 1.36 + if (ClassUnloading) { 1.37 1.38 - // Unload nmethods. 1.39 - CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class); 1.40 + // Unload classes and purge the SystemDictionary. 1.41 + bool purged_class = SystemDictionary::do_unloading(&GenMarkSweep::is_alive); 1.42 1.43 - // Prune dead klasses from subklass/sibling/implementor lists. 1.44 - Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); 1.45 + // Unload nmethods. 1.46 + CodeCache::do_unloading(&GenMarkSweep::is_alive, purged_class); 1.47 1.48 + // Prune dead klasses from subklass/sibling/implementor lists. 1.49 + Klass::clean_weak_klass_links(&GenMarkSweep::is_alive); 1.50 + } 1.51 // Delete entries for dead interned string and clean up unreferenced symbols in symbol table. 1.52 G1CollectedHeap::heap()->unlink_string_and_symbol_table(&GenMarkSweep::is_alive); 1.53
2.1 --- a/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Tue Jul 17 17:07:44 2018 +0200 2.2 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.cpp Fri Jul 20 03:07:49 2018 -0400 2.3 @@ -1,5 +1,5 @@ 2.4 /* 2.5 - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 2.6 + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. 2.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 2.8 * 2.9 * This code is free software; you can redistribute it and/or modify it 2.10 @@ -156,7 +156,7 @@ 2.11 } 2.12 2.13 process_vm_roots(strong_roots, weak_roots, phase_times, worker_i); 2.14 - 2.15 + process_string_table_roots(weak_roots, phase_times, worker_i); 2.16 { 2.17 // Now the CM ref_processor roots. 2.18 G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::CMRefRoots, worker_i); 2.19 @@ -223,18 +223,34 @@ 2.20 2.21 void G1RootProcessor::process_all_roots(OopClosure* oops, 2.22 CLDClosure* clds, 2.23 - CodeBlobClosure* blobs) { 2.24 + CodeBlobClosure* blobs, 2.25 + bool process_string_table) { 2.26 2.27 process_java_roots(oops, NULL, clds, clds, NULL, NULL, 0); 2.28 process_vm_roots(oops, oops, NULL, 0); 2.29 2.30 - if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) { 2.31 - CodeCache::blobs_do(blobs); 2.32 - } 2.33 + if (process_string_table) { 2.34 + process_string_table_roots(oops, NULL, 0); 2.35 + } 2.36 + process_code_cache_roots(blobs, NULL, 0); 2.37 2.38 _process_strong_tasks.all_tasks_completed(); 2.39 } 2.40 2.41 +void G1RootProcessor::process_all_roots(OopClosure* oops, 2.42 + CLDClosure* clds, 2.43 + CodeBlobClosure* blobs) { 2.44 + process_all_roots(oops, clds, blobs, true); 2.45 +} 2.46 + 2.47 +void G1RootProcessor::process_all_roots_no_string_table(OopClosure* oops, 2.48 + CLDClosure* clds, 2.49 + CodeBlobClosure* blobs) { 2.50 + assert(!ClassUnloading, "Should only be used when class unloading is disabled"); 2.51 + process_all_roots(oops, clds, blobs, false); 2.52 +} 2.53 + 2.54 + 2.55 void G1RootProcessor::process_java_roots(OopClosure* strong_roots, 2.56 CLDClosure* thread_stack_clds, 2.57 CLDClosure* strong_clds, 2.58 @@ -311,14 +327,23 @@ 2.59 SystemDictionary::roots_oops_do(strong_roots, weak_roots); 2.60 } 2.61 } 2.62 +} 2.63 2.64 - { 2.65 - G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::StringTableRoots, worker_i); 2.66 - // All threads execute the following. A specific chunk of buckets 2.67 - // from the StringTable are the individual tasks. 2.68 - if (weak_roots != NULL) { 2.69 - StringTable::possibly_parallel_oops_do(weak_roots); 2.70 - } 2.71 +void G1RootProcessor::process_string_table_roots(OopClosure* weak_roots, G1GCPhaseTimes* phase_times, 2.72 + uint worker_i) { 2.73 + assert(weak_roots != NULL, "Should only be called when all roots are processed"); 2.74 + 2.75 + G1GCParPhaseTimesTracker x(phase_times, G1GCPhaseTimes::StringTableRoots, worker_i); 2.76 + // All threads execute the following. A specific chunk of buckets 2.77 + // from the StringTable are the individual tasks. 2.78 + StringTable::possibly_parallel_oops_do(weak_roots); 2.79 +} 2.80 + 2.81 +void G1RootProcessor::process_code_cache_roots(CodeBlobClosure* code_closure, 2.82 + G1GCPhaseTimes* phase_times, 2.83 + uint worker_i) { 2.84 + if (!_process_strong_tasks.is_task_claimed(G1RP_PS_CodeCache_oops_do)) { 2.85 + CodeCache::blobs_do(code_closure); 2.86 } 2.87 } 2.88
3.1 --- a/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Tue Jul 17 17:07:44 2018 +0200 3.2 +++ b/src/share/vm/gc_implementation/g1/g1RootProcessor.hpp Fri Jul 20 03:07:49 2018 -0400 3.3 @@ -1,5 +1,5 @@ 3.4 /* 3.5 - * Copyright (c) 2015, Oracle and/or its affiliates. All rights reserved. 3.6 + * Copyright (c) 2015, 2018, Oracle and/or its affiliates. All rights reserved. 3.7 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 3.8 * 3.9 * This code is free software; you can redistribute it and/or modify it 3.10 @@ -34,6 +34,7 @@ 3.11 class G1CollectedHeap; 3.12 class G1GCPhaseTimes; 3.13 class G1ParPushHeapRSClosure; 3.14 +class G1RootClosures; 3.15 class Monitor; 3.16 class OopClosure; 3.17 class SubTasksDone; 3.18 @@ -71,6 +72,11 @@ 3.19 void worker_has_discovered_all_strong_classes(); 3.20 void wait_until_all_strong_classes_discovered(); 3.21 3.22 + void process_all_roots(OopClosure* oops, 3.23 + CLDClosure* clds, 3.24 + CodeBlobClosure* blobs, 3.25 + bool process_string_table); 3.26 + 3.27 void process_java_roots(OopClosure* scan_non_heap_roots, 3.28 CLDClosure* thread_stack_clds, 3.29 CLDClosure* scan_strong_clds, 3.30 @@ -84,6 +90,14 @@ 3.31 G1GCPhaseTimes* phase_times, 3.32 uint worker_i); 3.33 3.34 + void process_string_table_roots(OopClosure* scan_non_heap_weak_roots, 3.35 + G1GCPhaseTimes* phase_times, 3.36 + uint worker_i); 3.37 + 3.38 + void process_code_cache_roots(CodeBlobClosure* code_closure, 3.39 + G1GCPhaseTimes* phase_times, 3.40 + uint worker_i); 3.41 + 3.42 public: 3.43 G1RootProcessor(G1CollectedHeap* g1h); 3.44 3.45 @@ -114,6 +128,13 @@ 3.46 OopClosure* scan_non_heap_weak_roots, 3.47 uint worker_i); 3.48 3.49 + // Apply oops, clds and blobs to strongly and weakly reachable roots in the system, 3.50 + // the only thing different from process_all_roots is that we skip the string table 3.51 + // to avoid keeping every string live when doing class unloading. 3.52 + void process_all_roots_no_string_table(OopClosure* oops, 3.53 + CLDClosure* clds, 3.54 + CodeBlobClosure* blobs); 3.55 + 3.56 // Inform the root processor about the number of worker threads 3.57 void set_num_workers(int active_workers); 3.58 };
4.1 --- a/src/share/vm/runtime/arguments.cpp Tue Jul 17 17:07:44 2018 +0200 4.2 +++ b/src/share/vm/runtime/arguments.cpp Fri Jul 20 03:07:49 2018 -0400 4.3 @@ -1377,11 +1377,6 @@ 4.4 CFLS_LAB::modify_initialization(OldPLABSize, OldPLABWeight); 4.5 } 4.6 4.7 - if (!ClassUnloading) { 4.8 - FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false); 4.9 - FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false); 4.10 - } 4.11 - 4.12 if (PrintGCDetails && Verbose) { 4.13 tty->print_cr("MarkStackSize: %uk MarkStackSizeMax: %uk", 4.14 (unsigned int) (MarkStackSize / K), (uint) (MarkStackSizeMax / K)); 4.15 @@ -1748,6 +1743,13 @@ 4.16 // Keeping the heap 100% free is hard ;-) so limit it to 99%. 4.17 FLAG_SET_ERGO(uintx, MinHeapFreeRatio, 99); 4.18 } 4.19 + 4.20 + // If class unloading is disabled, also disable concurrent class unloading. 4.21 + if (!ClassUnloading) { 4.22 + FLAG_SET_CMDLINE(bool, CMSClassUnloadingEnabled, false); 4.23 + FLAG_SET_CMDLINE(bool, ClassUnloadingWithConcurrentMark, false); 4.24 + FLAG_SET_CMDLINE(bool, ExplicitGCInvokesConcurrentAndUnloadsClasses, false); 4.25 + } 4.26 #else // INCLUDE_ALL_GCS 4.27 assert(verify_serial_gc_flags(), "SerialGC unset"); 4.28 #endif // INCLUDE_ALL_GCS
5.1 --- /dev/null Thu Jan 01 00:00:00 1970 +0000 5.2 +++ b/test/gc/class_unloading/TestClassUnloadingDisabled.java Fri Jul 20 03:07:49 2018 -0400 5.3 @@ -0,0 +1,116 @@ 5.4 +/* 5.5 + * Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved. 5.6 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5.7 + * 5.8 + * This code is free software; you can redistribute it and/or modify it 5.9 + * under the terms of the GNU General Public License version 2 only, as 5.10 + * published by the Free Software Foundation. 5.11 + * 5.12 + * This code is distributed in the hope that it will be useful, but WITHOUT 5.13 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 5.14 + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 5.15 + * version 2 for more details (a copy is included in the LICENSE file that 5.16 + * accompanied this code). 5.17 + * 5.18 + * You should have received a copy of the GNU General Public License version 5.19 + * 2 along with this work; if not, write to the Free Software Foundation, 5.20 + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 5.21 + * 5.22 + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 5.23 + * or visit www.oracle.com if you need additional information or have any 5.24 + * questions. 5.25 + */ 5.26 + 5.27 +/* 5.28 + * @test 5.29 + * @key gc 5.30 + * @bug 8114823 5.31 + * @requires vm.gc == null 5.32 + * @requires vm.opt.ExplicitGCInvokesConcurrent != true 5.33 + * @requires vm.opt.ClassUnloading != true 5.34 + * @library /testlibrary /testlibrary/whitebox 5.35 + * @build sun.hotspot.WhiteBox 5.36 + * @run main ClassFileInstaller sun.hotspot.WhiteBox 5.37 + * sun.hotspot.WhiteBox$WhiteBoxPermission 5.38 + * 5.39 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 5.40 + * -XX:-ClassUnloading -XX:+UseG1GC TestClassUnloadingDisabled 5.41 + * 5.42 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 5.43 + * -XX:-ClassUnloading -XX:+UseSerialGC TestClassUnloadingDisabled 5.44 + * 5.45 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 5.46 + * -XX:-ClassUnloading -XX:+UseParallelGC TestClassUnloadingDisabled 5.47 + * 5.48 + * @run main/othervm -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 5.49 + * -XX:-ClassUnloading -XX:+UseConcMarkSweepGC TestClassUnloadingDisabled 5.50 + */ 5.51 + 5.52 +import java.io.File; 5.53 +import java.io.IOException; 5.54 +import java.nio.file.Files; 5.55 +import java.nio.file.Path; 5.56 +import java.nio.file.Paths; 5.57 + 5.58 +import sun.hotspot.WhiteBox; 5.59 + 5.60 +import com.oracle.java.testlibrary.Asserts; 5.61 + 5.62 +public class TestClassUnloadingDisabled { 5.63 + public static void main(String args[]) throws Exception { 5.64 + final WhiteBox wb = WhiteBox.getWhiteBox(); 5.65 + // Fetch the dir where the test class and the class 5.66 + // to be loaded resides. 5.67 + String classDir = TestClassUnloadingDisabled.class.getProtectionDomain().getCodeSource().getLocation().getPath(); 5.68 + String className = "ClassToLoadUnload"; 5.69 + 5.70 + Asserts.assertFalse(wb.isClassAlive(className), "Should not be loaded yet"); 5.71 + 5.72 + // The NoPDClassLoader handles loading classes in the test directory 5.73 + // and loads them without a protection domain, which in some cases 5.74 + // keeps the class live regardless of marking state. 5.75 + NoPDClassLoader nopd = new NoPDClassLoader(classDir); 5.76 + nopd.loadClass(className); 5.77 + 5.78 + Asserts.assertTrue(wb.isClassAlive(className), "Class should be loaded"); 5.79 + 5.80 + // Clear the class-loader, class and object references to make 5.81 + // class unloading possible. 5.82 + nopd = null; 5.83 + 5.84 + System.gc(); 5.85 + Asserts.assertTrue(wb.isClassAlive(className), "Class should not have ben unloaded"); 5.86 + } 5.87 +} 5.88 + 5.89 +class NoPDClassLoader extends ClassLoader { 5.90 + String path; 5.91 + 5.92 + NoPDClassLoader(String path) { 5.93 + this.path = path; 5.94 + } 5.95 + 5.96 + public Class<?> loadClass(String name) throws ClassNotFoundException { 5.97 + byte[] cls = null; 5.98 + File f = new File(path,name + ".class"); 5.99 + 5.100 + // Delegate class loading if class not present in the given 5.101 + // directory. 5.102 + if (!f.exists()) { 5.103 + return super.loadClass(name); 5.104 + } 5.105 + 5.106 + try { 5.107 + Path path = Paths.get(f.getAbsolutePath()); 5.108 + cls = Files.readAllBytes(path); 5.109 + } catch (IOException e) { 5.110 + throw new ClassNotFoundException(name); 5.111 + } 5.112 + 5.113 + // Define class with no protection domain and resolve it. 5.114 + return defineClass(name, cls, 0, cls.length, null); 5.115 + } 5.116 +} 5.117 + 5.118 +class ClassToLoadUnload { 5.119 +}