8208697: vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java fails with OutOfMemoryError: Metaspace
Summary: remove timeoutHandler class and let Stresser handle timeout, remove 30 threads filling metaspace, and remove related unused files.
Reviewed-by: lfoltan, mseledtsov
--- a/test/hotspot/jtreg/ProblemList.txt Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/ProblemList.txt Mon Sep 10 16:33:55 2018 -0400
@@ -214,11 +214,4 @@
vmTestbase/nsk/jdwp/ThreadReference/ForceEarlyReturn/forceEarlyReturn001/forceEarlyReturn001.java 7199837 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy007/TestDescription.java 8208697 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy008/TestDescription.java 8208697 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy009/TestDescription.java 8208697 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy010/TestDescription.java 8208697 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy011/TestDescription.java 8208697 generic-all
-vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java 8208697 generic-all
-
#############################################################################
--- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/PerformChecksHelper.java Mon Sep 10 16:33:55 2018 -0400
@@ -137,10 +137,10 @@
}
}
} catch (OutOfMemoryError e) {
- if (e.getMessage().trim().toLowerCase().contains("metadata")) {
- System.out.println("Got OOME in metaspace in PerformChecksHelper.callMethods(Class clazz). " +
- "This happened because reflection generates a too many accessors. " +
- "There is nothing we can do with it, so we are just suppressing.");
+ if (e.getMessage().trim().toLowerCase().contains("metaspace")) {
+ // avoid string concatenation, which may create more classes.
+ System.out.println("Got OOME in metaspace in PerformChecksHelper.callMethods(Class clazz). ");
+ System.out.println("This is possible with -triggerUnloadingByFillingMetaspace");
} else {
throw e;
}
--- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/StressHierarchyBaseClass.java Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/common/StressHierarchyBaseClass.java Mon Sep 10 16:33:55 2018 -0400
@@ -39,15 +39,13 @@
import nsk.share.test.ExecutionController;
import nsk.share.test.Stresser;
import nsk.share.test.TestBase;
-import nsk.share.test.timeoutwatchdog.TimeoutHandler;
-import nsk.share.test.timeoutwatchdog.TimeoutWatchdog;
/**
* Superclass for StressHierarchy* tests. It provides util methods to create and load
* classes hierarchy and perform checks.
*/
-abstract public class StressHierarchyBaseClass extends TestBase implements TimeoutHandler {
+abstract public class StressHierarchyBaseClass extends TestBase {
protected static String[] args;
@@ -101,7 +99,6 @@
long startTimeStamp = System.currentTimeMillis();
ExecutionController stresser = new Stresser(args);
stresser.start(1);
- TimeoutWatchdog.watch(stresser, this);
TreeDescriptor treeDescriptor = GenerateHierarchyHelper.generateHierarchy(treeDepth, minLevelSize, maxLevelSize, hierarchyType);
Tree tree = buildTree(treeDescriptor);
System.out.println("Generating took " + ((System.currentTimeMillis() - startTimeStamp)/1000) +" sec");
@@ -128,12 +125,6 @@
}
}
- @Override
- public void handleTimeout() {
- System.out.println("Shutting down vm because of time expired.");
- System.exit(95);
- }
-
abstract protected void runTestLogic(Tree tree, ExecutionController stresser) throws Throwable;
private Tree buildTree(TreeDescriptor treeDescriptor) throws MalformedURLException,
--- a/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/vmTestbase/metaspace/stressHierarchy/stressHierarchy012/TestDescription.java Mon Sep 10 16:33:55 2018 -0400
@@ -37,7 +37,7 @@
* @comment generate and compile metaspace.stressHierarchy.common.HumongousClass
* @run driver metaspace.stressHierarchy.common.GenClassesBuilder
* @run main/othervm
- * -XX:MaxMetaspaceSize=450m
+ * -XX:MaxMetaspaceSize=250m
* -Xss10m
* -Xbootclasspath/a:.
* -XX:+UnlockDiagnosticVMOptions
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/vmTestbase/nsk/share/classload/GeneratingClassLoader.java Mon Sep 10 16:33:55 2018 -0400
@@ -119,8 +119,6 @@
return bytecode;
} catch (UnsupportedEncodingException e) {
throw new TestBug(e);
- } catch (IOException e) {
- throw new TestBug(e);
}
}
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutHandler.java Mon Sep 10 12:48:57 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,36 +0,0 @@
-/*
- * Copyright (c) 2013, 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.share.test.timeoutwatchdog;
-
-/**
- * TimeoutHandler - interface to define reaction on timeout.
- * @see TimeoutWatchdoc
- */
-public interface TimeoutHandler {
-
- /**
- * Invoked when watchdog detects timeout. Subclasses must implement this method to define how timeout should be handled.
- */
- void handleTimeout();
-
-}
--- a/test/hotspot/jtreg/vmTestbase/nsk/share/test/timeoutwatchdog/TimeoutWatchdog.java Mon Sep 10 12:48:57 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,73 +0,0 @@
-/*
- * Copyright (c) 2013, 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.share.test.timeoutwatchdog;
-
-import nsk.share.test.ExecutionController;
-
-/**
- * This class watches for ExecutionControler and notifies TimeoutHander in case of timeout.
- */
-public class TimeoutWatchdog implements Runnable {
-
- private ExecutionController executionController;
-
- private TimeoutHandler handler;
-
- private static long CHECK_PERIOD = 1000; // In milliseconds
-
- private TimeoutWatchdog(ExecutionController executionController, TimeoutHandler handler) {
- this.executionController = executionController;
- this.handler = handler;
- }
-
- /**
- * Start watching for timeout.
- * This method runs a new daemon thread that checks periodically if the observable test is still running.
- * If timeout is detected <code>handler.handleTimeout()</code> will be called. If the test finishes normally the daemon
- * thread will silently die.
- * @param executionController - executionController used to monitor time left
- * @param handler - handler on which handleTimeout() will be called
- */
- public static void watch(ExecutionController executionController, TimeoutHandler handler) {
- Thread thread = new Thread(new TimeoutWatchdog(executionController, handler));
- thread.setName("TimeoutWatchdog_thread");
- thread.setDaemon(true);
- thread.start();
- }
-
- @Override
- public void run() {
- try {
- while (true) {
- Thread.sleep(CHECK_PERIOD);
- if (!executionController.continueExecution()) {
- System.out.println("Time expired. TimeoutWatchdog is calling TimeoutHandler.handleTimeout.");
- handler.handleTimeout();
- }
- }
- } catch (InterruptedException e) {
- throw new RuntimeException("Somebody dared to interrupt TimeoutWatchdog thread.");
- }
- }
-
-}
--- a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingHeap.java Mon Sep 10 12:48:57 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,69 +0,0 @@
-/*
- * Copyright (c) 2013, 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 vm.share.gc;
-
-import java.lang.management.ManagementFactory;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Random;
-
-import nsk.share.TestFailure;
-import nsk.share.test.ExecutionController;
-
-public class TriggerUnloadingByFillingHeap implements TriggerUnloadingHelper {
-
- public void triggerUnloading(ExecutionController stresser) {
- List<String> jvmArgs = ManagementFactory.getRuntimeMXBean().getInputArguments();
- if (jvmArgs.contains("-XX:+ExplicitGCInvokesConcurrent")) {
- throw new TestFailure("Test bug! Found -XX:+ExplicitGCInvokesConcurrent in jvm args. TriggerUnloadingByFillingHeap.triggerUnloading will not work!.");
- }
-
- System.out.println("collections invoked: " + provokeGC(stresser));
- System.out.println("collections invoked: " + provokeGC(stresser));
- System.out.println("collections invoked: " + provokeGC(stresser));
- }
-
- private static long getGCCounter() {
- return ManagementFactory.getGarbageCollectorMXBeans().get(1).getCollectionCount();
- }
-
- private static Random random = new Random();
-
- public static byte[] garbage; //make it reference public to avoid compiler optimizations
-
- private static long provokeGC(ExecutionController stresser) {
- long initCounter = getGCCounter();
- ArrayList<byte[]> list = new ArrayList<byte[]>();
- while (getGCCounter() == initCounter && stresser.continueExecution()) {
- list.add(new byte[1024]);
-
- garbage = new byte[1024];
- if (random.nextInt(10) % 10 < 3 && !list.isEmpty()) {
- list.remove(0);
- }
- System.gc();
- }
- return getGCCounter() - initCounter;
- }
-
-}
--- a/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java Mon Sep 10 12:48:57 2018 -0700
+++ b/test/hotspot/jtreg/vmTestbase/vm/share/gc/TriggerUnloadingByFillingMetaspace.java Mon Sep 10 16:33:55 2018 -0400
@@ -22,76 +22,38 @@
*/
package vm.share.gc;
-import java.util.ArrayList;
-import java.util.concurrent.Callable;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
+import nsk.share.test.ExecutionController;
import metaspace.stressHierarchy.common.exceptions.GotWrongOOMEException;
import nsk.share.gc.gp.classload.GeneratedClassProducer;
-import nsk.share.test.ExecutionController;
public class TriggerUnloadingByFillingMetaspace implements
TriggerUnloadingHelper {
- private static final int NUMBER_OF_THREADS = 30;
-
- private static class FillMetaspace {
- private volatile boolean gotOOME = false;
- private ExecutionController stresser;
- private final ThreadLocal<GeneratedClassProducer> generatedClassProducer =
- new ThreadLocal<GeneratedClassProducer>() {
- @Override
- protected GeneratedClassProducer initialValue() {
- return new GeneratedClassProducer("metaspace.stressHierarchy.common.HumongousClass");
- }
- };
-
- public FillMetaspace(ExecutionController stresser) { this.stresser = stresser; }
+ private volatile boolean gotOOME = false;
+ private ExecutionController stresser;
+ private final ThreadLocal<GeneratedClassProducer> generatedClassProducer =
+ new ThreadLocal<GeneratedClassProducer>() {
+ @Override
+ protected GeneratedClassProducer initialValue() {
+ return new GeneratedClassProducer("metaspace.stressHierarchy.common.HumongousClass");
+ }
+ };
- private class FillMetaspaceTask implements Callable<Object> {
- @Override
- public Object call() throws Exception {
- while (stresser.continueExecution() && ! gotOOME) {
- try {
- generatedClassProducer.get().create(-100500); //argument is not used.
- } catch (OutOfMemoryError oome) {
- if (!isInMetaspace(oome)) {
- throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid.");
- }
- gotOOME = true;
- }
- }
- return null;
- }
- }
- }
-
- private static boolean isInMetaspace(OutOfMemoryError error) {
- return error.getMessage().trim().toLowerCase().contains("metadata");
+ private static boolean isInMetaspace(Throwable error) {
+ return (error.getMessage().trim().toLowerCase().contains("metaspace"));
}
@Override
public void triggerUnloading(ExecutionController stresser) {
- try {
- FillMetaspace fillMetaspace = new FillMetaspace(stresser);
- ArrayList<Callable<Object>> tasks = new ArrayList<Callable<Object>>(NUMBER_OF_THREADS);
- for (int i = 0; i < NUMBER_OF_THREADS; i++) {
- tasks.add(fillMetaspace.new FillMetaspaceTask());
- }
- ExecutorService executorService = Executors.newCachedThreadPool();
+ while (stresser.continueExecution() && !gotOOME) {
try {
- executorService.invokeAll(tasks);
- } catch (InterruptedException e) {
- System.out.println("Process of gaining OOME in metaspace was interrupted.");
- e.printStackTrace();
+ generatedClassProducer.get().create(-100500); //argument is not used.
+ } catch (Throwable oome) {
+ if (!isInMetaspace(oome)) {
+ throw new GotWrongOOMEException("Got OOME in heap while triggering OOME in metaspace. Test result can't be valid.");
+ }
+ gotOOME = true;
}
- } catch (OutOfMemoryError e) {
- if (!isInMetaspace(e)) {
- throw new GotWrongOOMEException("Got OOME in heap while gaining OOME in metaspace. Test result can't be valid.");
- }
- return;
}
}
-
}
--- a/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/CompileAndDeoptimize.java Mon Sep 10 12:48:57 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,79 +0,0 @@
-/*
- * Copyright (c) 2012, 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 vm.share.vmstresser;
-
-public class CompileAndDeoptimize implements Runnable {
-
- public static int v = 0;
-
- private abstract static class A {
- public abstract void incv();
- }
-
- private static class B extends A {
- public void incv() {
- v++;
- }
- }
-
- public static class C extends A {
- public void incv() {
- v += (new int[1][1][1][1][1][1][1][1]).length;
- }
- }
-
- private volatile boolean done = false;
- public volatile A a = new B();
-
- private void incv() {
- a.incv();
- }
-
- private void inc() {
- while ( ! done ) {
- incv();
- }
- //while ( ! done ) {
- // incv();
- //}
- //while ( ! done ) {
- // incv();
- //}
- }
-
- public void run() {
- try {
- Thread t = new Thread(new Runnable() { @Override public void run() { inc(); } });
- t.start();
- Thread.sleep(100);
- a = (A) CompileAndDeoptimize.class.getClassLoader().loadClass(B.class.getName().replaceAll("B$", "C")).getConstructors()[0].newInstance(new Object[0]);
- //Thread.sleep(1000);
- //done = true;
- //t.join();
-
- } catch ( Throwable t ) {
- t.printStackTrace();
- }
- }
-
-}
--- a/test/hotspot/jtreg/vmTestbase/vm/share/vmstresser/MetaspaceStresser.java Mon Sep 10 12:48:57 2018 -0700
+++ /dev/null Thu Jan 01 00:00:00 1970 +0000
@@ -1,260 +0,0 @@
-/*
- * Copyright (c) 2013, 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 vm.share.vmstresser;
-
-import java.util.*;
-import java.util.concurrent.locks.*;
-
-import nsk.share.*;
-import nsk.share.classload.*;
-import nsk.share.test.*;
-
-/**
- * Stresser that load classes until OOME, then unload some of them and continue loading.
- */
-public class MetaspaceStresser extends Thread {
-
- /**
- * Capacity of class containers.
- * This amount of classes will be unloaded on reset call.
- */
- public static final int DEFAULT_BUCKET_SIZE = 4000;
-
- public static final int DEFAULT_PAUSE_TIME = 0;
-
- /*
- * Loaded classes stored in ClassContainer instances.
- * Such instances organized in array-based stack as it is
- * one of the simplest way to minimize possibility
- * to get OOME and guarntee that after replacing
- * reference to class container by null there will be
- * no cached refereces and container will be reclaimed by
- * GC and classes will become unloadable.
- */
- // Maximum available amount of arrays with class containers.
- private static final int CONTAINERS_ARRAY_LENGTH = 1000;
- // Maximum length array with class containers.
- private static final int CONTAINER_ARRAYS_COUNT = 100;
-
- private ClassContainersStack containersStack = new ClassContainersStack(CONTAINER_ARRAYS_COUNT * CONTAINERS_ARRAY_LENGTH,
- CONTAINERS_ARRAY_LENGTH);
- private ClassContainer newContainer = null;
-
- private ExecutionController controller = null;
- private int bucketSize = DEFAULT_BUCKET_SIZE;
- private int pauseTime = DEFAULT_PAUSE_TIME;
-
- private ReentrantLock lock = new ReentrantLock();
-
- /**
- * Construct MetaspaceStrresser with default bucket size
- * and pause time.
- * @param c controller to control execution time.
- */
- public MetaspaceStresser(ExecutionController c) {
- controller = c;
- }
-
- /**
- * Construct MetaspaceStrresser with custom bucket size
- * and pause time.
- * @param c controller to control execution time.
- * @param bucketSize classes to be unloaded on reset.
- * @param pauseTime pause after reset.
- */
- public MetaspaceStresser(ExecutionController c, int bucketSize, int pauseTime) {
- this(c);
- this.bucketSize = bucketSize;
- this.pauseTime = pauseTime;
- }
-
- /**
- * Fill Metaspace with classes.
- * Classes will be loaded until OOME, then some of them will be unloaded.
- */
- public synchronized void prepare() {
- while (controller.continueExecution()) {
- try {
- fillContainerStack();
- } catch (OutOfMemoryError oome) {
- unloadLastClassBucket();
- return;
- } catch (ClassNotFoundException cnfe) {
- throw new TestBug("Unexpected exception in stresser.", cnfe);
- }
- }
- }
-
- /**
- * Load new class to container, fill containerStack.
- * Classes will be loaded until OOME
- * @throws ClassNotFoundException
- */
- private void fillContainerStack() throws ClassNotFoundException {
- newContainer = new ClassContainer();
- while (newContainer.size() < bucketSize && controller.continueExecution()) {
- newContainer.loadClass();
- }
- containersStack.push(newContainer);
- newContainer = null;
- }
-
- /**
- * Run stresser.
- * Stresser will load classes until OOME, then bucketSize classes
- * will be unloaded and stresser will wait pauseTime millisiconds
- * before continuing class loading.
- */
- public void run() {
- try {
- while (controller.continueExecution()) {
- try {
- fillContainerStack();
- } catch (OutOfMemoryError oome) {
- unloadLastClassBucket();
- try {
- Thread.sleep(pauseTime);
- } catch (InterruptedException ie) {
- }
- }
- }
- } catch (Throwable e) {
- throw new TestBug("Unexpected exception in stresser.", e);
- } finally {
- containersStack.free();
- }
- }
-
- /**
- * Unload most recently loaded bucket of classes.
- */
- public void unloadLastClassBucket() {
- while (controller.continueExecution()) {
- try {
- containersStack.pop();
- System.gc();
- break;
- } catch (OutOfMemoryError oome) {
- oome.printStackTrace();
- continue;
- }
- }
- }
-
- /**
- * Array-based stack for ClassContainer's.
- */
- private class ClassContainersStack {
-
- private int arrayLength = 0;
- private int arraysCount = 0;
- private int arrayIndex = 0;
- private int elemIndex = 0;
-
- private ClassContainer data[][];
-
- /**
- * Create ClassContainersStack that will be able
- * to store size classes in arrays of segmentSize length.
- */
- public ClassContainersStack(int size, int segementSize) {
- arrayLength = segementSize;
- arraysCount = size / arrayLength;
- data = new ClassContainer[arraysCount][];
- data[0] = new ClassContainer[arrayLength];
- }
-
- /**
- * Push ClassContainer c into stack.
- */
- public synchronized void push(ClassContainer c) {
- data[arrayIndex][elemIndex] = c;
- elemIndex++;
- if (elemIndex == arrayLength) {
- if (arrayIndex == arraysCount) {
- throw new TestBug("ClassContainersStack ran out of available slots");
- }
- data[arrayIndex + 1] = new ClassContainer[arrayLength];
- arrayIndex++;
- elemIndex = 0;
- }
- }
-
- /**
- * Remove reference to top ClassContainer.
- */
- public synchronized void pop() {
- data[arrayIndex][elemIndex] = null;
- if (elemIndex > 0) {
- elemIndex--;
- } else if (arrayIndex > 0) {
- data[arrayIndex] = null;
- arrayIndex--;
- elemIndex = arrayLength - 1;
- }
- }
-
- /**
- * Remove all stored ClassContainers.
- */
- public synchronized void free() {
- data = null;
- System.gc();
- data = new ClassContainer[arraysCount][];
- data[0] = new ClassContainer[arrayLength];
- arrayIndex = 0;
- elemIndex = 0;
- }
-
- }
-
- /// Variable used to create uniqe name for generated classes.
- private static long lastClass = 0;
-
- /**
- * Class container consists of classes and their ClassLoader, so
- * if there will be no references to container and classes inside it then
- * it could be easely collected by GC.
- */
- private class ClassContainer {
-
- private List<Class> classes = new LinkedList<Class>();
- private GeneratingClassLoader loader = new GeneratingClassLoader();
- private String prefix = loader.getPrefix();
- private int length = loader.getNameLength();
-
- public void loadClass() throws ClassNotFoundException {
- String newName = prefix + "c" + lastClass;
- lastClass++;
- while (newName.length() < length) {
- newName = newName + "c";
- }
- classes.add(loader.loadClass(newName));
- }
-
- public int size() {
- return classes.size();
- }
- }
-
-}