TestHumongousClassLoader.java revision 12158:0fe2815ffa74
1/*
2 * Copyright (c) 2016, 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
24package gc.g1.humongousObjects;
25
26import gc.testlibrary.Helpers;
27import jdk.test.lib.Asserts;
28import sun.hotspot.WhiteBox;
29
30import java.io.IOException;
31import java.lang.reflect.InvocationTargetException;
32import java.net.URL;
33import java.net.URLClassLoader;
34import java.nio.file.Path;
35import java.nio.file.Paths;
36
37/**
38 * @test gc.g1.humongousObjects.TestHumongousClassLoader
39 * @summary Checks that unreachable classes and unreachable humongous class loader are unloaded after GC
40 * @requires vm.gc.G1
41 * @requires vm.opt.G1HeapRegionSize == "null" | vm.opt.G1HeapRegionSize == "1M"
42 * @requires vm.opt.ExplicitGCInvokesConcurrent != true
43 * @library /test/lib /
44 * @modules java.base/jdk.internal.misc
45 * @modules java.management
46 * @build sun.hotspot.WhiteBox
47 * @run driver ClassFileInstaller sun.hotspot.WhiteBox
48 *                                sun.hotspot.WhiteBox$WhiteBoxPermission
49 *
50 * @run main/othervm/timeout=240  -Xms256M -Xmx256M -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
51 *                                gc.g1.humongousObjects.ClassLoaderGenerator 1
52 *
53 * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
54 *                   -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC.log
55 *                   -XX:G1HeapRegionSize=1M
56 *                   gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC
57 *
58 * @run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
59 *                   -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_Full_GC_Mem_Pressure.log
60 *                   -XX:G1HeapRegionSize=1M
61 *                   gc.g1.humongousObjects.TestHumongousClassLoader FULL_GC_MEMORY_PRESSURE
62 *
63 *@run main/othervm -Xms256M -Xmx256M -XX:+UseG1GC -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI -Xbootclasspath/a:.
64 *                   -Xlog:class+load,class+unload=debug:file=TestHumongousClassLoader_CMC.log
65 *                   -XX:G1HeapRegionSize=1M -XX:MaxTenuringThreshold=1
66 *                   gc.g1.humongousObjects.TestHumongousClassLoader CMC
67 *
68 */
69
70public class TestHumongousClassLoader {
71
72    private static final WhiteBox WB = WhiteBox.getWhiteBox();
73    private static final String SAMPLE_CLASS_NAME_PREFIX = "SampleClassFiller";
74    public static final String SIMPLE_CLASSLOADER_NAME = "SimpleClassLoader";
75    public static final String HUMONGOUS_CLASSLOADER_NAME = "HumongousClassLoader";
76
77
78    public static final String LOAD_CLASS_METHOD_PROTOTYPE =
79            "    @Override\n"
80                    + "    public Class loadClass(String fileName) throws ClassNotFoundException {\n"
81                    + "        if (${ClassLoadFilter}) {\n"
82                    + "            System.out.println(\"Loading class \" + fileName);\n"
83                    + "            byte[] b = null;\n"
84                    + "            try {\n"
85                    + "                b = Files.readAllBytes(new File(fileName + \".class\").toPath());\n"
86                    + "            } catch (IOException e) {\n"
87                    + "                e.printStackTrace();\n"
88                    + "            }\n"
89                    + "            Class c = defineClass(fileName, b, 0, b.length);\n"
90                    + "            resolveClass(c);\n"
91                    + "            return c;\n"
92                    + "        } else {\n"
93                    + "            return super.loadClass(fileName);\n"
94                    + "        }\n"
95                    + "\n"
96                    + "\n"
97                    + "    }\n";
98
99    public static final String CLASS_HEADER = "import java.io.File;\n"
100            + "import java.io.IOException;\n"
101            + "import java.nio.file.Files;\n"
102            + "import java.nio.file.Paths;\n";
103
104    public static final String GENERIC_PROTOTYPE = "${ClassHeader}\n"
105            + "public class ${ClassName} extends ${BaseClass}{\n"
106            + "    ${ConstructorClause}\n"
107            + "    ${Methods}\n"
108            + "    ${Fields}\n"
109            + "}\n";
110
111    public static final String CONSTUCTOR_PROTOTYPE = "public ${ClassName}(ClassLoader parent) { super(parent);}\n";
112
113    private enum GC {
114        FULL_GC {
115            @Override
116            public void provoke() {
117                System.gc();
118            }
119        },
120        CMC {
121            @Override
122            public void provoke() {
123                // We need 2 young gc to promote class loader to old gen
124                // Otherwise it will not be unloaded after CMC
125                WHITE_BOX.youngGC();
126                Helpers.waitTillCMCFinished(WHITE_BOX, 0);
127                WHITE_BOX.youngGC();
128                Helpers.waitTillCMCFinished(WHITE_BOX, 0);
129                WHITE_BOX.g1StartConcMarkCycle();
130                Helpers.waitTillCMCFinished(WHITE_BOX, 0);
131            }
132        },
133        FULL_GC_MEMORY_PRESSURE {
134            @Override
135            public void provoke() {
136                WHITE_BOX.fullGC();
137            }
138        };
139        private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
140
141        public abstract void provoke();
142    }
143
144    public static void main(String[] args) throws ClassNotFoundException, InstantiationException,
145            IllegalAccessException, IOException, NoSuchMethodException, InvocationTargetException {
146
147        if (args.length != 1) {
148            throw new Error("Test Bug: Expected GC type wasn't provided as command line argument");
149        }
150        GC gc = GC.valueOf(args[0]);
151
152        Path wrkDir = Paths.get("");
153        URL[] url = {wrkDir.toUri().toURL()};
154        URLClassLoader urlLoader = new URLClassLoader(url);
155
156        Class<?> simpleClassLoaderClass = urlLoader.loadClass(SIMPLE_CLASSLOADER_NAME);
157
158        ClassLoader simpleClassLoader = (ClassLoader) simpleClassLoaderClass
159                .getConstructor(java.lang.ClassLoader.class)
160                .newInstance(TestHumongousClassLoader.class.getClassLoader());
161
162        // Sanity check
163        Asserts.assertEquals(WB.g1IsHumongous(simpleClassLoader), false,
164                "Test Bug: simpleClassLoader is expected to be non-humongous but it's humongous");
165
166
167        Class<?> humongousClassLoaderClass = simpleClassLoader.loadClass(HUMONGOUS_CLASSLOADER_NAME);
168
169        ClassLoader humongousClassLoader = (ClassLoader) humongousClassLoaderClass
170                .getConstructor(java.lang.ClassLoader.class)
171                .newInstance(simpleClassLoader);
172
173        // Sanity check
174        Asserts.assertEquals(WB.g1IsHumongous(humongousClassLoader), true,
175                "Test Bug: humongousClassLoader is expected to be humongous but it's non-humongous");
176
177        //Asserts.assertEquals(1,0);
178
179        Object[] loadedClasses = new Object[]{
180                G1SampleClass.LARGEST_NON_HUMONGOUS.getCls(humongousClassLoader, wrkDir, SAMPLE_CLASS_NAME_PREFIX)
181                        .newInstance(),
182                G1SampleClass.SMALLEST_HUMONGOUS.getCls(humongousClassLoader, wrkDir, SAMPLE_CLASS_NAME_PREFIX)
183                        .newInstance(),
184                G1SampleClass.ONE_REGION_HUMONGOUS.getCls(humongousClassLoader, wrkDir, SAMPLE_CLASS_NAME_PREFIX)
185                        .newInstance(),
186                G1SampleClass.TWO_REGION_HUMONGOUS.getCls(humongousClassLoader, wrkDir, SAMPLE_CLASS_NAME_PREFIX)
187                        .newInstance(),
188        };
189
190        // forgetting references to loaded classes
191        for (int i = 0; i < loadedClasses.length; ++i) {
192            loadedClasses[i] = null;
193        }
194
195        // forgetting referencies to classloaders
196        humongousClassLoader = null;
197        humongousClassLoaderClass = null;
198
199        simpleClassLoader = null;
200        simpleClassLoaderClass = null;
201
202        gc.provoke();
203
204        // Test checks
205        Asserts.assertEquals(WB.isClassAlive(HUMONGOUS_CLASSLOADER_NAME), false,
206                String.format("Classloader class %s is loaded after we forget all references to it",
207                        HUMONGOUS_CLASSLOADER_NAME));
208
209        for (G1SampleClass sampleClass : G1SampleClass.values()) {
210            String className = Helpers.enumNameToClassName(sampleClass.name()) + "Class";
211            Asserts.assertEquals(WB.isClassAlive(className), false,
212                    String.format("Class %s is loaded after we forget all references to it", className));
213        }
214    }
215
216}
217