8114823: G1 doesn't honor request to disable class unloading

Fri, 20 Jul 2018 03:07:49 -0400

author
fmatte
date
Fri, 20 Jul 2018 03:07:49 -0400
changeset 9358
6a4a6c499e89
parent 9357
0ef29304c2b4
child 9359
1c0a59cee0e4

8114823: G1 doesn't honor request to disable class unloading
Reviewed-by: tschatzl

src/share/vm/gc_implementation/g1/g1MarkSweep.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1RootProcessor.cpp file | annotate | diff | comparison | revisions
src/share/vm/gc_implementation/g1/g1RootProcessor.hpp file | annotate | diff | comparison | revisions
src/share/vm/runtime/arguments.cpp file | annotate | diff | comparison | revisions
test/gc/class_unloading/TestClassUnloadingDisabled.java file | annotate | diff | comparison | revisions
     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 +}

mercurial