Path: blob/master/test/hotspot/jtreg/vmTestbase/nsk/share/ClassUnloader.java
40948 views
/*1* Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation.7*8* This code is distributed in the hope that it will be useful, but WITHOUT9* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or10* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License11* version 2 for more details (a copy is included in the LICENSE file that12* accompanied this code).13*14* You should have received a copy of the GNU General Public License version15* 2 along with this work; if not, write to the Free Software Foundation,16* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.17*18* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA19* or visit www.oracle.com if you need additional information or have any20* questions.21*/2223/*24* Warning! Using this component need VM option -XX:-UseGCOverheadLimit25*26*/2728package nsk.share;2930import java.util.*;31import nsk.share.gc.gp.*;32import nsk.share.test.ExecutionController;33import nsk.share.test.Stresser;3435/**36* The <code>ClassUnloader</code> class allows to force VM to unload class(es)37* using memory stressing technique.38*39* <p>The method <code>unloadClass()</code> is provided which eats memory40* to enforce GC to cleanup the heap. So, if all references to a class41* and its loader are canceled, this may result in unloading the class.42*43* <p>ClassUnloader mainly intends to unload a class which was loaded44* with especial <code>ClassUnloader.loadClass()</code> method.45* A class is considered unloaded if its class loader is finalized.46* If there no finalization of class loader detected for some timeout,47* class is considered still loaded and method returns <i>false</i>.48*49* <p>Such finalization control applies only to a class loaded by50* ClassUnloader's <code>loadClass()</code> method. Otherwise, if there51* was no such class loaded, <code>unloadClass()</code> doesn't wait52* for a timeout and always returns <i>false</i>.53*54* <p>By default internal class loader of <code>CustomClassLoader</code> class55* is used for loading classes. This class loader can load class from .class file56* located in the specified directory.57* Application may define its own class loader, which may load classes using58* any other technique. Such class loader should be derived from base59* <code>CustomClassLoader</code> class, and set by <code>setClassLoader()</code>60* method.61*62* @see #setClassLoader(CustomClassLoader)63* @see #loadClass(String)64* @see #loadClass(String, String)65* @see #unloadClass()66*/67public class ClassUnloader {6869/**70* Class name of default class loader.71*/72public static final String INTERNAL_CLASS_LOADER_NAME = "nsk.share.CustomClassLoader";7374/**75* Whole amount of time in milliseconds to wait for class loader finalization.76*/77private static final int WAIT_TIMEOUT = 15000;7879/**80* Piece of time in milliseconds to wait in a loop for class loader finalization.81*/82private static final int WAIT_DELTA = 1000;8384/**85* Has class loader been finalized or not.86*/87volatile boolean finalized = false;8889/**90* Current class loader used for loading classes.91*/92private CustomClassLoader customClassLoader = null;9394/**95* List of classes loaded with current class loader.96*/97private Vector<Class<?>> classObjects = new Vector<Class<?>>();9899/**100* Class object of the first class been loaded with current class loader.101* To get the rest loaded classes use <code>getLoadedClass(int)</code>.102* The call <code>getLoadedClass()</code> is effectively equivalent to the call103* <code>getLoadedClass(0)</code>104*105* @return class object of the first loaded class.106*107* @see #getLoadedClass(int)108*/109public Class<?> getLoadedClass() {110return classObjects.get(0);111}112113/**114* Returns class objects at the specified index in the list of classes loaded115* with current class loader.116*117* @return class objects at the specified index.118*/119public Class<?> getLoadedClass(int index) {120return classObjects.get(index);121}122123/**124* Creates new instance of <code>CustomClassLoader</code> class as the current125* class loader and clears the list of loaded classes.126*127* @return created instance of <code>CustomClassLoader</code> class.128*129* @see #getClassLoader()130* @see #setClassLoader(CustomClassLoader)131*/132public CustomClassLoader createClassLoader() {133customClassLoader = new CustomClassLoader(this);134classObjects.removeAllElements();135136return customClassLoader;137}138139/**140* Sets new current class loader and clears the list of loaded classes.141*142* @see #getClassLoader()143* @see #createClassLoader()144*/145public void setClassLoader(CustomClassLoader customClassLoader) {146this.customClassLoader = customClassLoader;147classObjects.removeAllElements();148customClassLoader.setClassUnloader(this);149}150151/**152* Returns current class loader or <i>null</i> if not yet created or set.153*154* @return class loader object or null.155*156* @see #createClassLoader()157* @see #setClassLoader(CustomClassLoader)158*/159public CustomClassLoader getClassLoader() {160return customClassLoader;161}162163/**164* Loads class for specified class name using current class loader.165*166* <p>Current class loader should be set and capable to load class using only167* given class name. No other information such a location of .class files168* is passed to class loader.169*170* @param className name of class to load171*172* @throws ClassNotFoundException if no bytecode found for specified class name173* @throws Failure if current class loader is not specified;174* or if class was actually loaded with different class loader175*176* @see #loadClass(String, String)177*/178public void loadClass(String className) throws ClassNotFoundException {179180if (customClassLoader == null) {181throw new Failure("No current class loader defined");182}183184Class<?> cls = Class.forName(className, true, customClassLoader);185186// ensure that class was loaded by current class loader187if (cls.getClassLoader() != customClassLoader) {188throw new Failure("Class was loaded by unexpected class loader: " + cls.getClassLoader());189}190191classObjects.add(cls);192}193194/**195* Loads class from .class file located into specified directory using196* current class loader.197*198* <p>If there is no current class loader, then default class loader199* is created using <code>createClassLoader()</code>. Parameter <i>classDir</i>200* is passed to class loader using <code>CustomClassLoader.setClassPath()</code>201* method before loading class.202*203* @param className name of class to load204* @param classDir path to .class file location205*206* @throws ClassNotFoundException if no .class file found207* for specified class name208* @throws Failure if class was actually loaded with different class loader209*210* @see #loadClass(String)211* @see CustomClassLoader#setClassPath(String)212*/213public void loadClass(String className, String classDir) throws ClassNotFoundException {214215if (customClassLoader == null) {216createClassLoader();217}218219customClassLoader.setClassPath(classDir);220loadClass(className);221}222223/**224* Forces GC to unload previously loaded classes by cleaning all references225* to class loader with its loaded classes and eating memory.226*227* @return <i>true</i> if classes unloading has been detected228or <i>false</i> otherwise229*230* @throws Failure if exception other than OutOfMemoryError231* is thrown while eating memory232*233* @see #eatMemory()234*/235public boolean unloadClass(ExecutionController stresser) {236237finalized = false;238239// free references to class and class loader to be able for collecting by GC240long waitTimeout = (customClassLoader == null) ? 0 : WAIT_TIMEOUT;241classObjects.removeAllElements();242customClassLoader = null;243244// force class unloading by eating memory pool245eatMemory(stresser);246247// give GC chance to run and wait for finalization248long timeToFinish = System.currentTimeMillis() + waitTimeout;249while (!finalized && System.currentTimeMillis() < timeToFinish) {250if (!stresser.continueExecution()) {251return false;252}253try {254// suspend thread for a while255Thread.sleep(WAIT_DELTA);256} catch (InterruptedException e) {257throw new Failure("Unexpected InterruptedException while class unloading: " + e);258}259}260261// force GC to unload marked class loader and its classes262if (finalized) {263Runtime.getRuntime().gc();264return true;265}266267// class loader has not been finalized268return false;269}270271public boolean unloadClass() {272Stresser stresser = new Stresser() {273274@Override275public boolean continueExecution() {276return true;277}278279};280return unloadClass(stresser);281}282283/**284* Stresses memory by allocating arrays of bytes.285*286* Note that this method can throw Failure if any exception287* is thrown while eating memory. To avoid OOM while allocating288* exception we preallocate it before the lunch starts. It means289* that exception stack trace does not correspond to the place290* where exception is thrown, but points at start of the method.291*292* @throws Failure if exception other than OutOfMemoryError293* is thrown while eating memory294*/295public static void eatMemory(ExecutionController stresser) {296GarbageUtils.eatMemory(stresser, 50, 1024, 2);297298/*299* System.runFinalization() may potentially fail with OOM. This is why300* System.runFinalization() is repeated several times.301*/302for (int i = 0; i < 10; ++i) {303try {304if(!stresser.continueExecution()) {305return;306}307System.runFinalization();308break;309} catch (OutOfMemoryError e) {310}311}312}313314/**315* Stresses memory by allocating arrays of bytes.316*317* Note that this method can throw Failure if any exception318* is thrown while eating memory. To avoid OOM while allocating319* exception we preallocate it before the lunch starts. It means320* that exception stack trace does not correspond to the place321* where exception is thrown, but points at start of the method.322*323* @throws Failure if exception other than OutOfMemoryError324* is thrown while eating memory325*/326public static void eatMemory() {327Stresser stresser = new Stresser() {328329@Override330public boolean continueExecution() {331return true;332}333334};335GarbageUtils.eatMemory(stresser, 50, 1024, 2);336/*337* System.runFinalization() may potentially fail with OOM. This is why338* System.runFinalization() is repeated several times.339*/340for (int i = 0; i < 10; ++i) {341try {342if(!stresser.continueExecution()) {343return;344}345System.runFinalization();346break;347} catch (OutOfMemoryError e) {348}349}350}351}352353354