1 /*
2  * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * This code is free software; you can redistribute it and/or modify it
6  * under the terms of the GNU General Public License version 2 only, as
7  * published by the Free Software Foundation.
8  *
9  * This code is distributed in the hope that it will be useful, but WITHOUT
10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
12  * version 2 for more details (a copy is included in the LICENSE file that
13  * accompanied this code).
14  *
15  * You should have received a copy of the GNU General Public License version
16  * 2 along with this work; if not, write to the Free Software Foundation,
17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18  *
19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20  * or visit www.oracle.com if you need additional information or have any
21  * questions.
22  */
23 
24 package gc.class_unloading;
25 
26 /*
27  * @test
28  * @bug 8049831
29  * @requires vm.gc.G1
30  * @library /test/lib
31  * @modules java.base/jdk.internal.misc
32  *          java.management
33  * @build sun.hotspot.WhiteBox
34  * @run driver ClassFileInstaller sun.hotspot.WhiteBox
35  * @run driver gc.class_unloading.TestG1ClassUnloadingHWM
36  * @summary Test that -XX:-ClassUnloadingWithConcurrentMark will trigger a Full GC when more than MetaspaceSize metadata is allocated.
37  */
38 
39 import jdk.test.lib.process.OutputAnalyzer;
40 import jdk.test.lib.process.ProcessTools;
41 import sun.hotspot.WhiteBox;
42 
43 public class TestG1ClassUnloadingHWM {
44   private static long MetaspaceSize = 32 * 1024 * 1024;
45   private static long YoungGenSize  = 32 * 1024 * 1024;
46 
run(boolean enableUnloading)47   private static OutputAnalyzer run(boolean enableUnloading) throws Exception {
48     ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(
49       "-Xbootclasspath/a:.",
50       "-XX:+UnlockDiagnosticVMOptions",
51       "-XX:+WhiteBoxAPI",
52       "-XX:MetaspaceSize=" + MetaspaceSize,
53       "-Xmn" + YoungGenSize,
54       "-XX:+UseG1GC",
55       "-XX:" + (enableUnloading ? "+" : "-") + "ClassUnloadingWithConcurrentMark",
56       "-Xlog:gc",
57       TestG1ClassUnloadingHWM.AllocateBeyondMetaspaceSize.class.getName(),
58       "" + MetaspaceSize,
59       "" + YoungGenSize);
60     return new OutputAnalyzer(pb.start());
61   }
62 
runWithG1ClassUnloading()63   public static OutputAnalyzer runWithG1ClassUnloading() throws Exception {
64     return run(true);
65   }
66 
runWithoutG1ClassUnloading()67   public static OutputAnalyzer runWithoutG1ClassUnloading() throws Exception {
68     return run(false);
69   }
70 
testWithoutG1ClassUnloading()71   public static void testWithoutG1ClassUnloading() throws Exception {
72     // -XX:-ClassUnloadingWithConcurrentMark is used, so we expect a full GC instead of a concurrent cycle.
73     OutputAnalyzer out = runWithoutG1ClassUnloading();
74 
75     out.shouldMatch(".*Pause Full.*");
76     out.shouldNotMatch(".*Pause Young \\(Concurrent Start\\).*");
77   }
78 
testWithG1ClassUnloading()79   public static void testWithG1ClassUnloading() throws Exception {
80     // -XX:+ClassUnloadingWithConcurrentMark is used, so we expect a concurrent cycle instead of a full GC.
81     OutputAnalyzer out = runWithG1ClassUnloading();
82 
83     out.shouldMatch(".*Pause Young \\(Concurrent Start\\).*");
84     out.shouldNotMatch(".*Pause Full.*");
85   }
86 
main(String args[])87   public static void main(String args[]) throws Exception {
88     testWithG1ClassUnloading();
89     testWithoutG1ClassUnloading();
90   }
91 
92   public static class AllocateBeyondMetaspaceSize {
93     public static Object dummy;
94 
main(String [] args)95     public static void main(String [] args) throws Exception {
96       if (args.length != 2) {
97         throw new IllegalArgumentException("Usage: <MetaspaceSize> <YoungGenSize>");
98       }
99 
100       WhiteBox wb = WhiteBox.getWhiteBox();
101 
102       // Allocate past the MetaspaceSize limit
103       long metaspaceSize = Long.parseLong(args[0]);
104       long allocationBeyondMetaspaceSize  = metaspaceSize * 2;
105       long metaspace = wb.allocateMetaspace(null, allocationBeyondMetaspaceSize);
106 
107       long youngGenSize = Long.parseLong(args[1]);
108       triggerYoungGCs(youngGenSize);
109 
110       wb.freeMetaspace(null, metaspace, metaspace);
111     }
112 
triggerYoungGCs(long youngGenSize)113     public static void triggerYoungGCs(long youngGenSize) {
114       long approxAllocSize = 32 * 1024;
115       long numAllocations  = 2 * youngGenSize / approxAllocSize;
116 
117       for (long i = 0; i < numAllocations; i++) {
118         dummy = new byte[(int)approxAllocSize];
119       }
120     }
121   }
122 }
123 
124