1 /* 2 * Copyright (c) 2004, 2018, 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 /* 25 * @test 26 * @key stress gc 27 * 28 * @summary converted from VM Testbase gc/gctests/LargeObjects/large001. 29 * VM Testbase keywords: [gc, stress, stressopt, nonconcurrent, quick] 30 * VM Testbase readme: 31 * DESCRIPTION 32 * The test checks that Garbage Collector correctly does not throw any 33 * unexpected exceptions/errors while allocating large objects (classes 34 * that have more than 65535 fields and classes that have less than 65535 35 * fields). 65535 of fields is a limitation for JVM (see JVM specification 36 * Second edition 4.10). 37 * Since it is impossible to create one class with about 65535 of fields 38 * (javac cannot compile it), a child class extends a parent class, so the 39 * fields are devided into two subsets. However, the child class still has 40 * about 65535 of fields. 41 * The test starts a number of threads. This number is either set in *.cfg 42 * file or is calculated by the test itself based on the machine (see 43 * nsk.share.gc.Algorithms.getThreadsCount() method). As soon as all threads 44 * are started, each thread begins its checking. 45 * There are 13 classes to be loaded by each thread. These classes are 46 * generated by nsk.share.gc.Generator (see its javadoc for more details). 47 * Each class has a huge number of fields, but this number is less than the JVM 48 * limitation. 49 * The test loads the classes with nsk.share.gc.GCClassUnloader class that 50 * extends nsk.share.ClassUnloader and has a bit different algorith of eating 51 * heap. As soon as a class is loaded, the test creates an instance of 52 * it - allocates an object of that type. Then it drops references to the 53 * class and to the instance and tries to unload the class. The test does not 54 * expect any exceptions to be thrown. 55 * 56 * @library /vmTestbase 57 * /test/lib 58 * @run driver jdk.test.lib.FileInstaller . . 59 * 60 * @comment generate and compile nsk.share.gc.newclass.* classes 61 * @run driver nsk.share.gc.GenClassesBuilder 62 * 63 * @run main/othervm 64 * -XX:-UseGCOverheadLimit 65 * -Xlog:gc* 66 * gc.gctests.LargeObjects.large001.large001 67 * -largeClassesPath classes 68 * -isOverLimitFields false 69 * -aggregationDepth 0 70 * -t 1 71 */ 72 73 package gc.gctests.LargeObjects.large001; 74 75 import java.lang.reflect.*; 76 import java.lang.ref.WeakReference; 77 import java.util.*; 78 import nsk.share.TestFailure; 79 80 81 import nsk.share.gc.*; 82 import nsk.share.*; 83 84 public class large001 extends ThreadedGCTest { 85 86 // Package of the classes to be loaded 87 final static String PREFIX = "nsk.share.gc.newclass."; 88 // A bunch of classes that have number of fields more than JVM limitation 89 final static String[] LCLASSES = {PREFIX + "private_int_lchild", 90 PREFIX + "protected_short_lchild", 91 PREFIX + "public_long_lchild", 92 PREFIX + "public_Object_lchild", 93 PREFIX + "static_byte_lchild", 94 PREFIX + "static_float_lchild", 95 PREFIX + "transient_boolean_lchild", 96 PREFIX + "volatile_double_lchild", 97 PREFIX + "protected_combination_lchild", 98 PREFIX + "public_combination_lchild", 99 PREFIX + "static_combination_lchild", 100 PREFIX + "transient_combination_lchild", 101 PREFIX + "volatile_combination_lchild" 102 }; 103 // A bunch of classes that have number of fields less than JVM limitation 104 final static String[] SCLASSES = {PREFIX + "private_int_schild", 105 PREFIX + "protected_short_schild", 106 PREFIX + "public_long_schild", 107 PREFIX + "public_Object_schild", 108 PREFIX + "static_byte_schild", 109 PREFIX + "static_float_schild", 110 PREFIX + "transient_boolean_schild", 111 PREFIX + "volatile_double_schild", 112 PREFIX + "protected_combination_schild", 113 PREFIX + "public_combination_schild", 114 PREFIX + "static_combination_schild", 115 PREFIX + "transient_combination_schild", 116 PREFIX + "volatile_combination_schild" 117 }; 118 boolean isOverLimitFields = true; 119 int aggregationDepth = 0; 120 String largeClassesPath; 121 122 private class Worker implements Runnable { 123 124 int id; 125 126 public Worker(int id) { 127 this.id = id; 128 } 129 130 public void run() { 131 try { 132 // Use special ClassUnloader to load/unload classes 133 ClassUnloader unloader = new ClassUnloader(); 134 String[] classes = isOverLimitFields ? LCLASSES : SCLASSES; 135 136 for (String name : classes) { 137 // Load the class 138 log.debug(id + ": Loading class: " + name); 139 unloader.loadClass(name, largeClassesPath); 140 log.debug(id + ": Class loaded: " + name); 141 142 Class loadedClass = unloader.getLoadedClass(); 143 Object loadedClassInstance = loadedClass.newInstance(); 144 145 log.debug(id + ": Instance of the class: " + loadedClassInstance); 146 int depth = aggregationDepth; 147 List<WeakReference> refs = new ArrayList<WeakReference>(depth); 148 addObjRef(loadedClassInstance, loadedClass, depth, refs); 149 150 // Drop all references to the class and try to unload it 151 Algorithms.eatMemory(getExecutionController()); 152 log.debug(id + ": Testing non-null after GC force for: " + name); 153 if (loadedClass == null || loadedClassInstance == null) { 154 throw new Exception("Null class"); 155 } 156 verifyObjRef(loadedClassInstance, depth); 157 for (WeakReference ref : refs) { 158 if (ref.get() == null) { 159 throw new Exception("Unexpected null reference"); 160 } 161 } 162 refs = null; 163 loadedClass = null; 164 loadedClassInstance = null; 165 166 log.debug(id + ": Unloading class: " 167 + name); 168 boolean result = unloader.unloadClass(getExecutionController()); 169 log.debug(id + ": Result of uloading " 170 + "class " + name + ": " + result); 171 } 172 } catch (OutOfMemoryError oome) { 173 // just skip if we eat memory in several threads... 174 // rethrow in the case of one thread 175 if (runParams.getNumberOfThreads() == 1) { 176 throw oome; 177 } 178 } catch (Throwable t) { 179 throw new TestFailure("Unexpected exception: ", t); 180 } 181 } 182 183 // This method recursively create chain of aggregated objects for given object 184 public void addObjRef(Object object, Class clazz, int count, List<WeakReference> list) throws Throwable { 185 if (count == 0) { 186 return; 187 } 188 189 Field[] fields = object.getClass().getFields(); 190 for (Field field : fields) { 191 if (field.getName().startsWith("obj")) { 192 Object addedObject = clazz.newInstance(); 193 field.set(object, addedObject); 194 System.out.println("Added field " + field.getName() + " .... " + count); 195 addObjRef(addedObject, clazz, count - 1, list); 196 list.add(new WeakReference<Object>(addedObject)); 197 } 198 } 199 } 200 201 // This method recursively verfiy chain of aggregated objects for given object. 202 // Throws null pointer exception of objP/C field is null 203 public void verifyObjRef(Object object, int count) throws Throwable { 204 if (count == 0) { 205 return; 206 } 207 208 Field[] fields = object.getClass().getFields(); 209 for (Field field : fields) { 210 if (field.getName().startsWith("obj")) { 211 Object obj = field.get(object); 212 verifyObjRef(obj, count - 1); 213 } 214 } 215 } 216 } 217 218 public large001(String[] args) { 219 for (int i = 0; i < args.length; i++) { 220 if (args[i].equals("-largeClassesPath")) { 221 largeClassesPath = args[++i]; 222 } else if (args[i].equals("-isOverLimitFields")) { 223 isOverLimitFields = Boolean.getBoolean(args[++i]); 224 } else if (args[i].equals("-aggregationDepth")) { 225 aggregationDepth = Integer.parseInt(args[++i]); 226 } 227 } 228 if (largeClassesPath == null || largeClassesPath.length() == 0) { 229 throw new TestFailure("No classpath for large classes is given"); 230 } 231 } 232 233 @Override 234 protected Runnable createRunnable(int i) { 235 return new Worker(i); 236 } 237 238 @Override 239 public void run() { 240 if (isOverLimitFields) { 241 log.debug("Loading classes that have number " 242 + "of fields over limitation (more " 243 + "than 65535)"); 244 } else { 245 log.debug("Loading classes that have number " 246 + "of fields under limitation (less " 247 + "than 65535)"); 248 } 249 super.run(); 250 } 251 252 public static void main(String args[]) { 253 GC.runTest(new large001(args), args); 254 } 255 }