47bc94b60e
Reviewed-by: kvn, ihse, sspitsyn
292 lines
11 KiB
Java
292 lines
11 KiB
Java
/*
|
|
* Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
|
|
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
|
|
*
|
|
* This code is free software; you can redistribute it and/or modify it
|
|
* under the terms of the GNU General Public License version 2 only, as
|
|
* published by the Free Software Foundation.
|
|
*
|
|
* This code is distributed in the hope that it will be useful, but WITHOUT
|
|
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
|
|
* version 2 for more details (a copy is included in the LICENSE file that
|
|
* accompanied this code).
|
|
*
|
|
* You should have received a copy of the GNU General Public License version
|
|
* 2 along with this work; if not, write to the Free Software Foundation,
|
|
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
|
|
*
|
|
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
|
|
* or visit www.oracle.com if you need additional information or have any
|
|
* questions.
|
|
*/
|
|
|
|
package nsk.monitoring.share;
|
|
|
|
import java.util.*;
|
|
import nsk.share.log.Log;
|
|
import nsk.share.ClassUnloader;
|
|
import nsk.share.CustomClassLoader;
|
|
import nsk.share.test.Stresser;
|
|
|
|
/**
|
|
* The <code>ClassLoadingController</code> class allows to operate class
|
|
* loading/unloading process.
|
|
*/
|
|
public class ClassLoadingController extends StateControllerBase {
|
|
// Path and name of the classes to load
|
|
private static final String CLASSNAME_PATTERN = "nsk.monitoring.share.newclass.LoadableClass";
|
|
|
|
private int loadedClassCount = 100;
|
|
private int loaderCount = 1;
|
|
private boolean singleClass = true;
|
|
private String classDir;
|
|
private Hashtable<String, String[]> classesTable = new Hashtable<String, String[]>();
|
|
private ClassUnloader[] unloaders;
|
|
|
|
private Stresser stresser;
|
|
|
|
/**
|
|
* Constructs a new <code>ClassLoadingController</code> with defined
|
|
* arguments.
|
|
*
|
|
* @param log <code>Log</code> to print log info to.
|
|
* @param loadedClassCount number of classes to load.
|
|
* @param loaderCount number of loaders to use.
|
|
* @param singleClass if class loaders are instances of the same class.
|
|
* @param classDir directory to load classes from.
|
|
*/
|
|
public ClassLoadingController(
|
|
Log log,
|
|
int loadedClassCount,
|
|
int loaderCount,
|
|
boolean singleClass,
|
|
String classDir,
|
|
Stresser stresser
|
|
) {
|
|
super(log);
|
|
setLoadedClassCount(loadedClassCount);
|
|
setLoaderCount(loaderCount);
|
|
setClassDir(classDir);
|
|
singleClassLoaderClass(singleClass);
|
|
dump();
|
|
preloadAllClasses();
|
|
setStresser(stresser);
|
|
}
|
|
|
|
private void setStresser(Stresser stresser) {
|
|
this.stresser = stresser;
|
|
}
|
|
|
|
public ClassLoadingController(Log log, ArgumentHandler argHandler, Stresser stresser) {
|
|
this(
|
|
log,
|
|
argHandler.getLoadableClassesCount(),
|
|
// argHandler.getLoadersCount(),
|
|
(int)stresser.getMaxIterations(),
|
|
argHandler.singleClassloaderClass(),
|
|
argHandler.getRawArgument(0),
|
|
stresser
|
|
);
|
|
}
|
|
|
|
public void dump() {
|
|
log.debug("classes to be loaded:\t" + loadedClassCount);
|
|
log.debug("classloader instances:\t" + loaderCount);
|
|
if (singleClass)
|
|
log.debug("classloader class:\tsingle");
|
|
else
|
|
log.debug("classloader class:\ttwo");
|
|
log.debug("Class dir" + classDir);
|
|
|
|
}
|
|
|
|
private void setLoadedClassCount(int loadedClassCount) {
|
|
this.loadedClassCount = loadedClassCount;
|
|
}
|
|
|
|
// Set loaderCount value
|
|
private void setLoaderCount(int loaderCount) {
|
|
this.loaderCount = loaderCount;
|
|
}
|
|
|
|
// Set singleClass value
|
|
private void singleClassLoaderClass(boolean singleClass) {
|
|
this.singleClass = singleClass;
|
|
}
|
|
|
|
// Set classDir value
|
|
private void setClassDir(String classDir) {
|
|
this.classDir = classDir;
|
|
}
|
|
|
|
// Load classes
|
|
private void preloadAllClasses() {
|
|
log.debug("preloading all classes...");
|
|
if (singleClass)
|
|
createUnloaders(1);
|
|
else
|
|
createUnloaders(2);
|
|
|
|
for (int i = 0; i < unloaders.length; i++) {
|
|
loadClasses(unloaders[i], 1, false);
|
|
unloaders[i].unloadClass();
|
|
}
|
|
}
|
|
|
|
// Load classes
|
|
private boolean loadClasses(ClassUnloader unloader, int classCount, boolean doKeep) {
|
|
String newClassName;
|
|
String[] classNames = new String[classCount + 1];
|
|
classNames[0] = unloader.getClassLoader().getClass().getName()
|
|
+ "@"
|
|
+ Integer.toHexString(
|
|
unloader.getClassLoader().hashCode()
|
|
);
|
|
|
|
|
|
for (int i = 1; i <= classCount; i++) {
|
|
newClassName = CLASSNAME_PATTERN + int2Str(i);
|
|
classNames[i] = newClassName;
|
|
try {
|
|
unloader.loadClass(newClassName);
|
|
} catch (ClassNotFoundException e) {
|
|
log.error(e.toString());
|
|
e.printStackTrace();
|
|
return false;
|
|
}
|
|
}
|
|
if (doKeep)
|
|
classesTable.put(String.valueOf(unloader.hashCode()), classNames);
|
|
return true;
|
|
} // loadClasses()
|
|
|
|
/**
|
|
* Loads all classes.
|
|
*
|
|
* @see ClassLoadingController#ClassLoadingController
|
|
*/
|
|
public int loadClasses() {
|
|
CustomClassLoader loader;
|
|
boolean res = true;
|
|
String loaderName;
|
|
|
|
createUnloaders(loaderCount);
|
|
|
|
int count = 0;
|
|
for (int i = 0; i < unloaders.length; i++) {
|
|
loaderName = unloaders[i].getClassLoader().getClass().getName()
|
|
+ "@"
|
|
+ Integer.toHexString(
|
|
unloaders[i].getClassLoader().hashCode()
|
|
);
|
|
if (loadClasses(unloaders[i], loadedClassCount, true)) {
|
|
String[] values = (String[])
|
|
classesTable.get(String.valueOf(unloaders[i].hashCode()));
|
|
int length = values.length - 1;
|
|
log.debug(loaderName + "(" + i + ")>>> " + length
|
|
+ " classes have been loaded");
|
|
count += length;
|
|
}
|
|
}
|
|
log.info("Total: loading is performed " + count + " times");
|
|
|
|
return count;
|
|
}
|
|
|
|
// Unload classes
|
|
public int unloadClasses() {
|
|
String loaderName;
|
|
int count = 0;
|
|
long timeLeft = 0;
|
|
|
|
for (int i = 0; i < loaderCount && (timeLeft = stresser.getTimeLeft()/1000) > 0; i++) {
|
|
loaderName = unloaders[i].getClassLoader().getClass().getName()
|
|
+ "@"
|
|
+ Integer.toHexString(
|
|
unloaders[i].getClassLoader().hashCode()
|
|
);
|
|
String hashCode = String.valueOf(unloaders[i].hashCode());
|
|
String[] values = (String[]) classesTable.get(hashCode);
|
|
|
|
if (unloaders[i].unloadClass()) {
|
|
int length = values.length - 1;
|
|
count += length;
|
|
log.debug(loaderName + "(" + i + ")>>> " + length
|
|
+ " classes have been unloaded (time left: "+timeLeft+" s)");
|
|
classesTable.remove(hashCode);
|
|
} else {
|
|
log.debug(loaderName + "(" + i + ")>>> "
|
|
+ "classes couldn't be unloaded (time left: "+timeLeft+" s)");
|
|
}
|
|
}
|
|
|
|
log.info("Total: unloading is performed " + count + " times");
|
|
|
|
return count;
|
|
}
|
|
|
|
private void createUnloaders(int count) {
|
|
CustomClassLoader loader;
|
|
unloaders = new ClassUnloader[count];
|
|
|
|
for (int i = 0; i < count; i++) {
|
|
unloaders[i] = new ClassUnloader();
|
|
if (singleClass) {
|
|
loader = unloaders[i].createClassLoader();
|
|
} else {
|
|
if (i%2 == 0)
|
|
loader = new ClassLoaderA();
|
|
else
|
|
loader = new ClassLoaderB();
|
|
unloaders[i].setClassLoader(loader);
|
|
}
|
|
loader.setClassPath(classDir);
|
|
} // for
|
|
}
|
|
|
|
/**
|
|
* Brings out VM into defined state. The method loads all classes via
|
|
* {@link ClassLoadingController#loadClasses}.
|
|
*
|
|
* @see ClassLoadingController#loadClasses
|
|
*/
|
|
public void run() {
|
|
loadClasses();
|
|
}
|
|
|
|
/**
|
|
* Tries to reclaim VM into initial state. The method tries to load all
|
|
* classes via {@link ClassLoadingController#unloadClasses}.
|
|
*
|
|
* @see ClassLoadingController#unloadClasses
|
|
*/
|
|
public void reset() {
|
|
unloadClasses();
|
|
}
|
|
|
|
// The class extends CustomClassLoader with specific implementation of
|
|
// toString() method
|
|
class ClassLoaderA extends CustomClassLoader {
|
|
public ClassLoaderA() {
|
|
super();
|
|
}
|
|
|
|
public String toString() {
|
|
return "ClassLoaderA";
|
|
}
|
|
} // ClassLoaderA
|
|
|
|
// The class extends CustomClassLoader with specific implementation of
|
|
// toString() method
|
|
class ClassLoaderB extends CustomClassLoader {
|
|
public ClassLoaderB() {
|
|
super();
|
|
}
|
|
|
|
public String toString() {
|
|
return "ClassLoaderB";
|
|
}
|
|
} // ClassLoaderB
|
|
}
|