1 /* 2 * Copyright (c) 2003, 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 package nsk.monitoring.share; 25 26 import java.util.*; 27 import nsk.share.log.Log; 28 import nsk.share.ClassUnloader; 29 import nsk.share.CustomClassLoader; 30 import nsk.share.test.Stresser; 31 32 /** 33 * The <code>ClassLoadingController</code> class allows to operate class 34 * loading/unloading process. 35 */ 36 public class ClassLoadingController extends StateControllerBase { 37 // Path and name of the classes to load 38 private static final String CLASSNAME_PATTERN = "nsk.monitoring.share.newclass.LoadableClass"; 39 40 private int loadedClassCount = 100; 41 private int loaderCount = 1; 42 private boolean singleClass = true; 43 private String classDir; 44 private Hashtable<String, String[]> classesTable = new Hashtable<String, String[]>(); 45 private ClassUnloader[] unloaders; 46 47 private Stresser stresser; 48 49 /** 50 * Constructs a new <code>ClassLoadingController</code> with defined 51 * arguments. 52 * 53 * @param log <code>Log</code> to print log info to. 54 * @param loadedClassCount number of classes to load. 55 * @param loaderCount number of loaders to use. 56 * @param singleClass if class loaders are instances of the same class. 57 * @param classDir directory to load classes from. 58 */ ClassLoadingController( Log log, int loadedClassCount, int loaderCount, boolean singleClass, String classDir, Stresser stresser )59 public ClassLoadingController( 60 Log log, 61 int loadedClassCount, 62 int loaderCount, 63 boolean singleClass, 64 String classDir, 65 Stresser stresser 66 ) { 67 super(log); 68 setLoadedClassCount(loadedClassCount); 69 setLoaderCount(loaderCount); 70 setClassDir(classDir); 71 singleClassLoaderClass(singleClass); 72 dump(); 73 preloadAllClasses(); 74 setStresser(stresser); 75 } 76 setStresser(Stresser stresser)77 private void setStresser(Stresser stresser) { 78 this.stresser = stresser; 79 } 80 ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser)81 public ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser) { 82 this( 83 log, 84 argHandler.getLoadableClassesCount(), 85 // argHandler.getLoadersCount(), 86 (int)stresser.getMaxIterations(), 87 argHandler.singleClassloaderClass(), 88 argHandler.getRawArgument(0), 89 stresser 90 ); 91 } 92 dump()93 public void dump() { 94 log.debug("classes to be loaded:\t" + loadedClassCount); 95 log.debug("classloader instances:\t" + loaderCount); 96 if (singleClass) 97 log.debug("classloader class:\tsingle"); 98 else 99 log.debug("classloader class:\ttwo"); 100 log.debug("Class dir" + classDir); 101 102 } 103 setLoadedClassCount(int loadedClassCount)104 private void setLoadedClassCount(int loadedClassCount) { 105 this.loadedClassCount = loadedClassCount; 106 } 107 108 // Set loaderCount value setLoaderCount(int loaderCount)109 private void setLoaderCount(int loaderCount) { 110 this.loaderCount = loaderCount; 111 } 112 113 // Set singleClass value singleClassLoaderClass(boolean singleClass)114 private void singleClassLoaderClass(boolean singleClass) { 115 this.singleClass = singleClass; 116 } 117 118 // Set classDir value setClassDir(String classDir)119 private void setClassDir(String classDir) { 120 this.classDir = classDir; 121 } 122 123 // Load classes preloadAllClasses()124 private void preloadAllClasses() { 125 log.debug("preloading all classes..."); 126 if (singleClass) 127 createUnloaders(1); 128 else 129 createUnloaders(2); 130 131 for (int i = 0; i < unloaders.length; i++) { 132 loadClasses(unloaders[i], 1, false); 133 unloaders[i].unloadClass(); 134 } 135 } 136 137 // Load classes loadClasses(ClassUnloader unloader, int classCount, boolean doKeep)138 private boolean loadClasses(ClassUnloader unloader, int classCount, boolean doKeep) { 139 String newClassName; 140 String[] classNames = new String[classCount + 1]; 141 classNames[0] = unloader.getClassLoader().getClass().getName() 142 + "@" 143 + Integer.toHexString( 144 unloader.getClassLoader().hashCode() 145 ); 146 147 148 for (int i = 1; i <= classCount; i++) { 149 newClassName = CLASSNAME_PATTERN + int2Str(i); 150 classNames[i] = newClassName; 151 try { 152 unloader.loadClass(newClassName); 153 } catch (ClassNotFoundException e) { 154 log.error(e.toString()); 155 e.printStackTrace(); 156 return false; 157 } 158 } 159 if (doKeep) 160 classesTable.put(String.valueOf(unloader.hashCode()), classNames); 161 return true; 162 } // loadClasses() 163 164 /** 165 * Loads all classes. 166 * 167 * @see ClassLoadingController#ClassLoadingController 168 */ loadClasses()169 public int loadClasses() { 170 CustomClassLoader loader; 171 boolean res = true; 172 String loaderName; 173 174 createUnloaders(loaderCount); 175 176 int count = 0; 177 for (int i = 0; i < unloaders.length; i++) { 178 loaderName = unloaders[i].getClassLoader().getClass().getName() 179 + "@" 180 + Integer.toHexString( 181 unloaders[i].getClassLoader().hashCode() 182 ); 183 if (loadClasses(unloaders[i], loadedClassCount, true)) { 184 String[] values = (String[]) 185 classesTable.get(String.valueOf(unloaders[i].hashCode())); 186 int length = values.length - 1; 187 log.debug(loaderName + "(" + i + ")>>> " + length 188 + " classes have been loaded"); 189 count += length; 190 } 191 } 192 log.info("Total: loading is performed " + count + " times"); 193 194 return count; 195 } 196 197 // Unload classes unloadClasses()198 public int unloadClasses() { 199 String loaderName; 200 int count = 0; 201 long timeLeft = 0; 202 203 for (int i = 0; i < loaderCount && (timeLeft = stresser.getTimeLeft()/1000) > 0; i++) { 204 loaderName = unloaders[i].getClassLoader().getClass().getName() 205 + "@" 206 + Integer.toHexString( 207 unloaders[i].getClassLoader().hashCode() 208 ); 209 String hashCode = String.valueOf(unloaders[i].hashCode()); 210 String[] values = (String[]) classesTable.get(hashCode); 211 212 if (unloaders[i].unloadClass()) { 213 int length = values.length - 1; 214 count += length; 215 log.debug(loaderName + "(" + i + ")>>> " + length 216 + " classes have been unloaded (time left: "+timeLeft+" s)"); 217 classesTable.remove(hashCode); 218 } else { 219 log.debug(loaderName + "(" + i + ")>>> " 220 + "classes couldn't be unloaded (time left: "+timeLeft+" s)"); 221 } 222 } 223 224 log.info("Total: unloading is performed " + count + " times"); 225 226 return count; 227 } 228 createUnloaders(int count)229 private void createUnloaders(int count) { 230 CustomClassLoader loader; 231 unloaders = new ClassUnloader[count]; 232 233 for (int i = 0; i < count; i++) { 234 unloaders[i] = new ClassUnloader(); 235 if (singleClass) { 236 loader = unloaders[i].createClassLoader(); 237 } else { 238 if (i%2 == 0) 239 loader = new ClassLoaderA(); 240 else 241 loader = new ClassLoaderB(); 242 unloaders[i].setClassLoader(loader); 243 } 244 loader.setClassPath(classDir); 245 } // for 246 } 247 248 /** 249 * Brings out VM into defined state. The method loads all classes via 250 * {@link ClassLoadingController#loadClasses}. 251 * 252 * @see ClassLoadingController#loadClasses 253 */ run()254 public void run() { 255 loadClasses(); 256 } 257 258 /** 259 * Tries to reclaim VM into initial state. The method tries to load all 260 * classes via {@link ClassLoadingController#unloadClasses}. 261 * 262 * @see ClassLoadingController#unloadClasses 263 */ reset()264 public void reset() { 265 unloadClasses(); 266 } 267 268 // The class extends CustomClassLoader with specific implementation of 269 // toString() method 270 class ClassLoaderA extends CustomClassLoader { ClassLoaderA()271 public ClassLoaderA() { 272 super(); 273 } 274 toString()275 public String toString() { 276 return "ClassLoaderA"; 277 } 278 } // ClassLoaderA 279 280 // The class extends CustomClassLoader with specific implementation of 281 // toString() method 282 class ClassLoaderB extends CustomClassLoader { ClassLoaderB()283 public ClassLoaderB() { 284 super(); 285 } 286 toString()287 public String toString() { 288 return "ClassLoaderB"; 289 } 290 } // ClassLoaderB 291 } 292