s++] = "Failure: CloneNotSupportedException";
exitCode = 2; // FAILED
} catch (CloneNotSupportedException cnse) {
if (TRACE_ON)
log[messages++] = "Success: CloneNotSupportedException";
pool[index++] = cnse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: CloneNotSupportedException";
pool[index++] = oome;
skipped++;
};
// Check IllegalAccessException (positive):
try {
int junkIt = abraIntegerField.getInt(null); // legal - should pass
// int junkIt = abraPrivateField.getInt(null); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalAccessException (positive)";
} catch (IllegalAccessException iae) {
log[messages++] = "Failure: IllegalAccessException (positive)";
pool[index++] = iae;
exitCode = 2;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalAccessException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalAccessException (negative):
try {
// int junkIt = abraIntegerField.getInt(null); // legal - should pass
int junkIt = abraPrivateField.getInt(null); // illegal - should fail
log[messages++] = "Failure: IllegalAccessException (negative)";
exitCode = 2; // FAILED
} catch (IllegalAccessException iae) {
if (TRACE_ON)
log[messages++] = "Success: IllegalAccessException (negative)";
pool[index++] = iae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalAccessException (negative)";
pool[index++] = oome;
skipped++;
};
// Check IllegalArgumentException (positive):
try {
int junkIt = abraIntegerField.getInt(null); // legal - should pass
// int junkIt = abraBooleanField.getInt(null); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalArgumentException (positive)";
} catch (IllegalAccessException iae) {
log[messages++] =
"Failure: IllegalArgumentException (positive) incorrectly thrown
IllegalAccessException";
pool[index++] = iae;
exitCode = 2;
} catch (IllegalArgumentException iae) {
log[messages++] = "Failure: IllegalArgumentException (positive)";
pool[index++] = iae;
exitCode = 2;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalArgumentException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalArgumentException (negative):
try {
// int junkIt = abraIntegerField.getInt(null); // legal - should pass
int junkIt = abraBooleanField.getInt(null); // illegal - should fail
log[messages++] = "Failure: IllegalArgumentException (negative)";
exitCode = 2; // FAILED
} catch (IllegalAccessException iae) {
log[messages++] =
"Failure: IllegalArgumentException (negative) incorrectly thrown
IllegalAccessException";
pool[index++] = iae;
exitCode = 2;
} catch (IllegalArgumentException iae) {
if (TRACE_ON)
log[messages++] = "Success: IllegalArgumentException (negative)";
pool[index++] = iae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalArgumentException (negative)";
pool[index++] = oome;
skipped++;
};
// Check IllegalMonitorStateException (positive):
try {
synchronized (cadabra) {
cadabra.notifyAll(); // legal - should pass
};
// cadabra.notifyAll(); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalMonitorStateException (positive)";
} catch (IllegalMonitorStateException imse) {
log[messages++] = "Failure: IllegalMonitorStateException (positive)";
exitCode = 2;
pool[index++] = imse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalMonitorStateException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalMonitorStateException (negative):
try {
// synchronized (cadabra) {
// cadabra.notifyAll(); // legal - should pass
// };
cadabra.notifyAll(); // illegal - should fail
log[messages++] = "Failure: IllegalMonitorStateException (negative)";
exitCode = 2;
} catch (IllegalMonitorStateException imse) {
if (TRACE_ON)
log[messages++] = "Success: IllegalMonitorStateException (negative)";
pool[index++] = imse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalMonitorStateException (negative)";
pool[index++] = oome;
skipped++;
};
return exitCode;
};
/**
* Re-call to <code>run(args,out)</code>, and return JCK-like exit status.
* (The stream <code>out</code> is assigned to <code>System.out</code> here.)
* @see #run(String[],PrintStream)
*/
public static void main (String args[]) {
int exitCode = run(args,System.out);
System.exit(exitCode + 95);
// JCK-like exit status.
};
/**
* This class should be used to check <code>CloneNotSupportedException</code>,
* <code>IllegalAccessException</code>, and
<code>IllegalArgumentException</code>.
* The class extends <code>except004</code> in order that its (protected)
* method <code>clone()</code> be available from <code>except004</code>.
*/
private static class Abra extends except004 {
/**
* Will try to incorrectly find this class as <code>Cadabra</code>
* instead of <code>Abra$Cadabra</code>.
*/
public static class Cadabra implements Cloneable {
};
/**
* Will try to incorrectly access to this field from outside this class.
*/
private static final int DONT_TOUCH_ME = 666;
/**
* Will try to incorrectly access to this field from outside this class.
*/
public static final int MAIN_CYR_NUMBER = 47;
/**
* Will try to get this field like <code>int<code> zero.
*/
public static final boolean NOT_AN_INTEGER = false;
/**
* Will try to correctly instantiate <code>Abra.Cadabra</code>,
* not <code>Abra</code>.
*/
private Abra () {
};
/**
* Yet another constructor, which is <code>public</code>.
*/
public Abra (String nothingSpecial) {
};
};
}
======================================================================
Name: elC94547 Date: 08/22/99
JCK 1.3N classic VM (win32) throws OutOfMemoryError while
trying to execute an operation like:
log[messages++] = "some constant string";
This problem prevents the classic VM from passing the test:
nsk/stress/except/except004
which could be found in the HotSpot's testbase:
/net/sqesvr/vsn/testbase/testbase_nsk
Below the slightly modified variant of the program "except004.java"
is displayed. The only modifications are the try-catch parentheses
enwrapping the proboscis portion of code, and the "return" operator
intended to stop execution of the test just after the problem is
demonstrated.
The test "except004" eats (almost) all memory available in the heap,
and then provokes several exceptions in order to check exceptions
handling when there is apparently no free memory to create new
Throwable instance.
Since there is no free memory, the test does not print any messages
while performing testing. Instead, necessary message strings are
stored into the log[] array especially pre-allocated before the
testing begins. Messages themselves are constant strings, so that
operation of storing new message into the log[] should not consume
any heap memory.
However, such harmless operation like:
log[messages++] = "Success: ArrayIndexOutOfBoundsException";
seems to throw OutOfMemoryError.
When I compiled the displayed below program with JDK 1.3N (win32)
and executed it with classic VM, I obtained the following output:
>>>> javac except004.java
>>>> java -classic except004
# While printing this message, JVM seems to initiate the output
# stream, so that it will not need more memory to print later,
# when the heap would fail to provide more memory.
#
# Note, that the test maintains especial static log[] field in
# order to avoid printing when the heap seems exhausted.
# Nevertheless, printing could arise OutOfMemoryError even
# after all the memory allocated by the test is released.
#
# That problem is caused by the known JDK/HotSpot bugs:
# 4239841 (P1/S5) 1.1: poor garbage collector performance
# 4245060 (P4/S5) poor garbage collector performance
#
# This message is just intended to work-around that problem.
# If printing should fail even so, the test will return the
# exit status 96 instead of 97 to indicate the problem.
pool[520282]=new Object(); // elapsed 1.111s
pool[1044282]=new Object(); // elapsed 1.282s
pool[1568587]=new Object(); // elapsed 1.712s
pool[1673651]=new Object(); // elapsed 1.111s
pool[1674467]=new Object(); // elapsed 1.111s
pool[1674473]=new Object(); // elapsed 1.112s
pool[1674474]=new Object(); // elapsed 1.111s
pool[1674475]=new Object(); // elapsed 1.112s
pool[1674476]=new Object(); // elapsed 2.223s
pool[1674477]=new Object(); // elapsed 2.223s
pool[1674478]=new Object(); // elapsed 2.234s
pool[1674479]=new Object(); // elapsed 2.223s
pool[1674480]=new Object(); // elapsed 3.334s
pool[1674481]=new Object(); // elapsed 4.447s
Exception in thread "main" java.lang.RuntimeException: oops --
ArrayIndexOutOfBoundsException
But, when I commented away a couple of lines marked with
/*A*/ in the "except004.java" source, the test passed:
>>>> javac except004.java
>>>> java -classic except004
# While printing this message, JVM seems to initiate the output
# stream, so that it will not need more memory to print later,
# when the heap would fail to provide more memory.
#
# Note, that the test maintains especial static log[] field in
# order to avoid printing when the heap seems exhausted.
# Nevertheless, printing could arise OutOfMemoryError even
# after all the memory allocated by the test is released.
#
# That problem is caused by the known JDK/HotSpot bugs:
# 4239841 (P1/S5) 1.1: poor garbage collector performance
# 4245060 (P4/S5) poor garbage collector performance
#
# This message is just intended to work-around that problem.
# If printing should fail even so, the test will return the
# exit status 96 instead of 97 to indicate the problem.
pool[520282]=new Object(); // elapsed 1.122s
pool[1044282]=new Object(); // elapsed 1.282s
pool[1568587]=new Object(); // elapsed 1.703s
pool[1673651]=new Object(); // elapsed 1.101s
pool[1674467]=new Object(); // elapsed 1.102s
pool[1674473]=new Object(); // elapsed 1.111s
pool[1674474]=new Object(); // elapsed 1.112s
pool[1674475]=new Object(); // elapsed 1.112s
pool[1674476]=new Object(); // elapsed 2.223s
pool[1674477]=new Object(); // elapsed 2.223s
pool[1674478]=new Object(); // elapsed 2.233s
pool[1674479]=new Object(); // elapsed 2.223s
pool[1674480]=new Object(); // elapsed 3.345s
pool[1674481]=new Object(); // elapsed 4.447s
Heap seems exhausted - OutOfMemoryError thrown.
Success: ArithmeticException
Test passed.
This looks like classic VM consumes some amount of heap memory
for its internal needs while trying to execute the operation:
log[messages++] = "Success: ArrayIndexOutOfBoundsException";
But I believe, that internal features of virtual machine should
not cause OutOfMemoryError when the executed Java code is not
trying to allocate memory.
Following win32 VMs also suffer this problem:
JDK 1.2 (noJIT), JDK 1.2.1 (noJIT), JDK 1.2.2 (noJIT),
JDK 1.3.0A (classic).
However, JDK 1.3N (hotspot) and JDK 1.3.0A (hotspot) pass
the test "except004".
I used the following computer to demonstrate this bug:
- Pentium 350MHz, 128Mb RAM, Windows NT 4.0 Workstation, Service Pack 3
Following is the source of the program "except004.java":
/* @(#)except004.java 1.1 99/06/29
* Copyright 99/06/29 Sun Microsystems, Inc.
*/
import java.io.*;
import java.lang.reflect.*;
/**
* This checks if various exceptions are thrown (and caught) correctly
* when there apparently are no free space in the heap to allocate new
* <code>Throwable</code> instance.
*
* <p>The test tries to occupy all of memory available in the heap by
* allocating lots of new <code>Object()</code> instances. Instances of the
* type <code>Object</code> are the smallest objects, so they apparently should
* occupy most fine-grained fragments in the heap and leave no free space for
* new <code>Throwable</code> instance. After that, the test provokes various
* exceptions (e.g.: by executing integer division by 0 and so on), and checks
* if appropriate exceptions are thrown.
*
* <p>Note, that memory occupation is terminated if memory allocation slows
* down crucially. This is a workaround intended to avoid the HotSpot bug:
* <br>
* #4248801 (P1/S5) slow memory allocation when heap is almost exhausted
*
* <p>There is also a workaround involved to avoid the following bugs known
* for HotSpot and for classic VM:
* <br>
* #4239841 (P1/S5) 1.1: poor garbage collector performance
* <br>
* #4245060 (P4/S5) poor garbage collector performance
* <br>However, printing of the test's error messages, warnings, and of
* execution trace may fail even so. If the test fails due to poor GC
* performance, exit status 96 is returned instead of 97.
*
* <p>Also note, that the test needs a lot of memory to start up, so it should
* not run under older JDK 1.1.x release due to its poor heap utilization.
*
* @author Eugene I. Latkin
*/
public class except004 {
/**
* Either allow or supress printing of execution trace.
*/
private static final boolean TRACE_ON = true; // false;
/**
* Either allow or supress printing of warning messages.
*/
private static final boolean WARN_ON = true;
/**
* Temporary <code>log</code> for error messages, warnings and/or execution
trace.
* @see #messages
*/
private static String log[] = new String [1000]; // up to 1000 messages
/**
* How many <code>messages</code> were submitted to the <code>log</code>.
* @see #log
*/
private static int messages = 0;
/**
* Re-call to the method <code>run(out)</code> (ignore <code>args[]</code>),
* and print the test summary - either test passed of failed.
*/
public static int run (String args[], PrintStream out) {
int exitCode;
try {
exitCode = run(out);
} catch (OutOfMemoryError oome) {
exitCode = 2;
log[messages++] = "java.lang.OutOfMemoryError in run(out)";
};
// Print the log[] and the test summary:
try {
for (int i=0; i<messages; i++)
out.println(log[i]);
if (exitCode == 0) {
if (TRACE_ON)
out.println("Test passed.");
} else
out.println("Test failed.");
} catch (OutOfMemoryError oome) {
// Poor performance of garbage collector:
exitCode = 1;
};
return exitCode;
};
/**
* Allocate as much <code>Object</code> instances as possible to bring JVM
* into stress, and then check if exceptions are correctly thrown accordingly
* to various situations like integer division by 0, etc.
*/
private static int run (PrintStream out) {
out.println("# While printing this message, JVM seems to initiate the
output");
out.println("# stream, so that it will not need more memory to print
later,");
out.println("# when the heap would fail to provide more memory.");
out.println("# ");
out.println("# Note, that the test maintains especial static log[] field
in");
out.println("# order to avoid printing when the heap seems exhausted.");
out.println("# Nevertheless, printing could arise OutOfMemoryError even");
out.println("# after all the memory allocated by the test is released.");
out.println("# ");
out.println("# That problem is caused by the known JDK/HotSpot bugs:");
out.println("# 4239841 (P1/S5) 1.1: poor garbage collector performance");
out.println("# 4245060 (P4/S5) poor garbage collector performance");
out.println("# ");
out.println("# This message is just intended to work-around that problem.");
out.println("# If printing should fail even so, the test will return the");
out.println("# exit status 96 instead of 97 to indicate the problem.");
// Prepare some items, which will be used by the test:
Object stringArray[] = new String [1];
Object integerValue = new Integer(0);
Object doubleValue = new Double(0);
Object trash = null;
Field abraPrivateField;
Field abraIntegerField;
Field abraBooleanField;
try {
abraPrivateField = Abra.class.getDeclaredField("DONT_TOUCH_ME");
abraIntegerField = Abra.class.getDeclaredField("MAIN_CYR_NUMBER");
abraBooleanField = Abra.class.getDeclaredField("NOT_AN_INTEGER");
} catch (NoSuchFieldException nsfe) {
out.println("Test initaition failed: field not found in class Abra");
return 2;
};
Abra abra = new Abra("via public constructor");
Abra.Cadabra cadabra = new Abra.Cadabra();
// Allocate repository for a lots of tiny objects:
Object pool[];
int poolSize = 1<<23; // ~8 millions
try {
pool = new Object [poolSize];
} catch (OutOfMemoryError oome) {
out.println("No enough memory to initiate the test.");
out.println("Test failed.");
return 2;
};
int index = 0;
// Sum up time spent, when it was hard to JVM to allocate next object
// (i.e.: when JVM has spent more than 1 second to allocate new object):
double totalDelay = 0;
long timeMark = System.currentTimeMillis();
try {
for (; index<poolSize; index++) {
//-------------------------
pool[index] = new Object();
long nextTimeMark = System.currentTimeMillis();
long elapsed = nextTimeMark - timeMark;
timeMark = nextTimeMark;
//----------------------
if (elapsed > 1000) {
double seconds = elapsed / 1000.0;
if (TRACE_ON)
out.println(
"pool[" + index + "]=new Object(); // elapsed " + seconds
+ "s");
totalDelay += seconds;
if (totalDelay > 60) {
if (TRACE_ON)
out.println(
"Memory allocation became slow; so, heap seems
exhausted.");
break;
};
};
};
} catch (OutOfMemoryError oome) {
if (TRACE_ON)
log[messages++] = "Heap seems exhausted - OutOfMemoryError thrown.";
// Do not release any byte once allocated:
pool[index++] = oome;
};
if (index > poolSize-1000) {
if (WARN_ON)
log[messages++] = "Warning: pool[] is full; so, checks would not be
enough hard...";
};
// Sum up exit code:
int exitCode=0; // apparently PASSED
int skipped=0; // some checks may correctly suffer OutOfMemoryError
// Check ArithmeticException:
try {
int x,y,z;
x = y = 0;
z = x / y;
log[messages++] = "Failure: ArithmeticException";
exitCode = 2; // FAILED
} catch (ArithmeticException ae) {
if (TRACE_ON)
log[messages++] = "Success: ArithmeticException";
pool[index++] = ae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArithmeticException";
pool[index++] = oome;
skipped++;
};
/**************************************************************************/
try {
/***
*** Start proboscis block:
***/
// Check ArrayIndexOutOfBoundsException:
try {
pool[poolSize] = pool[index-1];
log[messages++] = "Failure: ArrayIndexOutOfBoundsException";
exitCode = 2; // FAILED
} catch (ArrayIndexOutOfBoundsException aioobe) {
/*A*/ if (TRACE_ON)
/*A*/ log[messages++] = "Success: ArrayIndexOutOfBoundsException";
pool[index++] = aioobe;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArrayIndexOutOfBoundsException";
pool[index++] = oome;
skipped++;
};
/***
*** Error is caught here:
***/
} catch (OutOfMemoryError oops) {
throw new RuntimeException("oops -- ArrayIndexOutOfBoundsException");
};
if (messages >= 0)
return 0;
/***************************************************************************/
// Check ArrayStoreException:
try {
stringArray[0] = integerValue;
log[messages++] = "Failure: ArrayStoreException";
exitCode = 2; // FAILED
} catch (ArrayStoreException ase) {
if (TRACE_ON)
log[messages++] = "Success: ArrayStoreException";
pool[index++] = ase;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArrayStoreException";
pool[index++] = oome;
skipped++;
};
// Check ClassCastException:
try {
trash = (Double) integerValue;
log[messages++] = "Failure: ClassCastException";
exitCode = 2; // FAILED
} catch (ClassCastException cce) {
if (TRACE_ON)
log[messages++] = "Success: ClassCastException";
pool[index++] = cce;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ClassCastException";
pool[index++] = oome;
skipped++;
};
// Check CloneNotSupportedException:
try {
trash = abra.clone(); // illegal - should fail
// trash = cadabra.clone(); // legal - should pass
log[message
exitCode = 2; // FAILED
} catch (CloneNotSupportedException cnse) {
if (TRACE_ON)
log[messages++] = "Success: CloneNotSupportedException";
pool[index++] = cnse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: CloneNotSupportedException";
pool[index++] = oome;
skipped++;
};
// Check IllegalAccessException (positive):
try {
int junkIt = abraIntegerField.getInt(null); // legal - should pass
// int junkIt = abraPrivateField.getInt(null); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalAccessException (positive)";
} catch (IllegalAccessException iae) {
log[messages++] = "Failure: IllegalAccessException (positive)";
pool[index++] = iae;
exitCode = 2;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalAccessException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalAccessException (negative):
try {
// int junkIt = abraIntegerField.getInt(null); // legal - should pass
int junkIt = abraPrivateField.getInt(null); // illegal - should fail
log[messages++] = "Failure: IllegalAccessException (negative)";
exitCode = 2; // FAILED
} catch (IllegalAccessException iae) {
if (TRACE_ON)
log[messages++] = "Success: IllegalAccessException (negative)";
pool[index++] = iae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalAccessException (negative)";
pool[index++] = oome;
skipped++;
};
// Check IllegalArgumentException (positive):
try {
int junkIt = abraIntegerField.getInt(null); // legal - should pass
// int junkIt = abraBooleanField.getInt(null); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalArgumentException (positive)";
} catch (IllegalAccessException iae) {
log[messages++] =
"Failure: IllegalArgumentException (positive) incorrectly thrown
IllegalAccessException";
pool[index++] = iae;
exitCode = 2;
} catch (IllegalArgumentException iae) {
log[messages++] = "Failure: IllegalArgumentException (positive)";
pool[index++] = iae;
exitCode = 2;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalArgumentException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalArgumentException (negative):
try {
// int junkIt = abraIntegerField.getInt(null); // legal - should pass
int junkIt = abraBooleanField.getInt(null); // illegal - should fail
log[messages++] = "Failure: IllegalArgumentException (negative)";
exitCode = 2; // FAILED
} catch (IllegalAccessException iae) {
log[messages++] =
"Failure: IllegalArgumentException (negative) incorrectly thrown
IllegalAccessException";
pool[index++] = iae;
exitCode = 2;
} catch (IllegalArgumentException iae) {
if (TRACE_ON)
log[messages++] = "Success: IllegalArgumentException (negative)";
pool[index++] = iae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalArgumentException (negative)";
pool[index++] = oome;
skipped++;
};
// Check IllegalMonitorStateException (positive):
try {
synchronized (cadabra) {
cadabra.notifyAll(); // legal - should pass
};
// cadabra.notifyAll(); // illegal - should fail
if (TRACE_ON)
log[messages++] = "Success: IllegalMonitorStateException (positive)";
} catch (IllegalMonitorStateException imse) {
log[messages++] = "Failure: IllegalMonitorStateException (positive)";
exitCode = 2;
pool[index++] = imse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalMonitorStateException (positive)";
pool[index++] = oome;
skipped++;
};
// Check IllegalMonitorStateException (negative):
try {
// synchronized (cadabra) {
// cadabra.notifyAll(); // legal - should pass
// };
cadabra.notifyAll(); // illegal - should fail
log[messages++] = "Failure: IllegalMonitorStateException (negative)";
exitCode = 2;
} catch (IllegalMonitorStateException imse) {
if (TRACE_ON)
log[messages++] = "Success: IllegalMonitorStateException (negative)";
pool[index++] = imse;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: IllegalMonitorStateException (negative)";
pool[index++] = oome;
skipped++;
};
return exitCode;
};
/**
* Re-call to <code>run(args,out)</code>, and return JCK-like exit status.
* (The stream <code>out</code> is assigned to <code>System.out</code> here.)
* @see #run(String[],PrintStream)
*/
public static void main (String args[]) {
int exitCode = run(args,System.out);
System.exit(exitCode + 95);
// JCK-like exit status.
};
/**
* This class should be used to check <code>CloneNotSupportedException</code>,
* <code>IllegalAccessException</code>, and
<code>IllegalArgumentException</code>.
* The class extends <code>except004</code> in order that its (protected)
* method <code>clone()</code> be available from <code>except004</code>.
*/
private static class Abra extends except004 {
/**
* Will try to incorrectly find this class as <code>Cadabra</code>
* instead of <code>Abra$Cadabra</code>.
*/
public static class Cadabra implements Cloneable {
};
/**
* Will try to incorrectly access to this field from outside this class.
*/
private static final int DONT_TOUCH_ME = 666;
/**
* Will try to incorrectly access to this field from outside this class.
*/
public static final int MAIN_CYR_NUMBER = 47;
/**
* Will try to get this field like <code>int<code> zero.
*/
public static final boolean NOT_AN_INTEGER = false;
/**
* Will try to correctly instantiate <code>Abra.Cadabra</code>,
* not <code>Abra</code>.
*/
private Abra () {
};
/**
* Yet another constructor, which is <code>public</code>.
*/
public Abra (String nothingSpecial) {
};
};
}
======================================================================
Name: elC94547 Date: 08/22/99
JCK 1.3N classic VM (win32) throws OutOfMemoryError while
trying to execute an operation like:
log[messages++] = "some constant string";
This problem prevents the classic VM from passing the test:
nsk/stress/except/except004
which could be found in the HotSpot's testbase:
/net/sqesvr/vsn/testbase/testbase_nsk
Below the slightly modified variant of the program "except004.java"
is displayed. The only modifications are the try-catch parentheses
enwrapping the proboscis portion of code, and the "return" operator
intended to stop execution of the test just after the problem is
demonstrated.
The test "except004" eats (almost) all memory available in the heap,
and then provokes several exceptions in order to check exceptions
handling when there is apparently no free memory to create new
Throwable instance.
Since there is no free memory, the test does not print any messages
while performing testing. Instead, necessary message strings are
stored into the log[] array especially pre-allocated before the
testing begins. Messages themselves are constant strings, so that
operation of storing new message into the log[] should not consume
any heap memory.
However, such harmless operation like:
log[messages++] = "Success: ArrayIndexOutOfBoundsException";
seems to throw OutOfMemoryError.
When I compiled the displayed below program with JDK 1.3N (win32)
and executed it with classic VM, I obtained the following output:
>>>> javac except004.java
>>>> java -classic except004
# While printing this message, JVM seems to initiate the output
# stream, so that it will not need more memory to print later,
# when the heap would fail to provide more memory.
#
# Note, that the test maintains especial static log[] field in
# order to avoid printing when the heap seems exhausted.
# Nevertheless, printing could arise OutOfMemoryError even
# after all the memory allocated by the test is released.
#
# That problem is caused by the known JDK/HotSpot bugs:
# 4239841 (P1/S5) 1.1: poor garbage collector performance
# 4245060 (P4/S5) poor garbage collector performance
#
# This message is just intended to work-around that problem.
# If printing should fail even so, the test will return the
# exit status 96 instead of 97 to indicate the problem.
pool[520282]=new Object(); // elapsed 1.111s
pool[1044282]=new Object(); // elapsed 1.282s
pool[1568587]=new Object(); // elapsed 1.712s
pool[1673651]=new Object(); // elapsed 1.111s
pool[1674467]=new Object(); // elapsed 1.111s
pool[1674473]=new Object(); // elapsed 1.112s
pool[1674474]=new Object(); // elapsed 1.111s
pool[1674475]=new Object(); // elapsed 1.112s
pool[1674476]=new Object(); // elapsed 2.223s
pool[1674477]=new Object(); // elapsed 2.223s
pool[1674478]=new Object(); // elapsed 2.234s
pool[1674479]=new Object(); // elapsed 2.223s
pool[1674480]=new Object(); // elapsed 3.334s
pool[1674481]=new Object(); // elapsed 4.447s
Exception in thread "main" java.lang.RuntimeException: oops --
ArrayIndexOutOfBoundsException
But, when I commented away a couple of lines marked with
/*A*/ in the "except004.java" source, the test passed:
>>>> javac except004.java
>>>> java -classic except004
# While printing this message, JVM seems to initiate the output
# stream, so that it will not need more memory to print later,
# when the heap would fail to provide more memory.
#
# Note, that the test maintains especial static log[] field in
# order to avoid printing when the heap seems exhausted.
# Nevertheless, printing could arise OutOfMemoryError even
# after all the memory allocated by the test is released.
#
# That problem is caused by the known JDK/HotSpot bugs:
# 4239841 (P1/S5) 1.1: poor garbage collector performance
# 4245060 (P4/S5) poor garbage collector performance
#
# This message is just intended to work-around that problem.
# If printing should fail even so, the test will return the
# exit status 96 instead of 97 to indicate the problem.
pool[520282]=new Object(); // elapsed 1.122s
pool[1044282]=new Object(); // elapsed 1.282s
pool[1568587]=new Object(); // elapsed 1.703s
pool[1673651]=new Object(); // elapsed 1.101s
pool[1674467]=new Object(); // elapsed 1.102s
pool[1674473]=new Object(); // elapsed 1.111s
pool[1674474]=new Object(); // elapsed 1.112s
pool[1674475]=new Object(); // elapsed 1.112s
pool[1674476]=new Object(); // elapsed 2.223s
pool[1674477]=new Object(); // elapsed 2.223s
pool[1674478]=new Object(); // elapsed 2.233s
pool[1674479]=new Object(); // elapsed 2.223s
pool[1674480]=new Object(); // elapsed 3.345s
pool[1674481]=new Object(); // elapsed 4.447s
Heap seems exhausted - OutOfMemoryError thrown.
Success: ArithmeticException
Test passed.
This looks like classic VM consumes some amount of heap memory
for its internal needs while trying to execute the operation:
log[messages++] = "Success: ArrayIndexOutOfBoundsException";
But I believe, that internal features of virtual machine should
not cause OutOfMemoryError when the executed Java code is not
trying to allocate memory.
Following win32 VMs also suffer this problem:
JDK 1.2 (noJIT), JDK 1.2.1 (noJIT), JDK 1.2.2 (noJIT),
JDK 1.3.0A (classic).
However, JDK 1.3N (hotspot) and JDK 1.3.0A (hotspot) pass
the test "except004".
I used the following computer to demonstrate this bug:
- Pentium 350MHz, 128Mb RAM, Windows NT 4.0 Workstation, Service Pack 3
Following is the source of the program "except004.java":
/* @(#)except004.java 1.1 99/06/29
* Copyright 99/06/29 Sun Microsystems, Inc.
*/
import java.io.*;
import java.lang.reflect.*;
/**
* This checks if various exceptions are thrown (and caught) correctly
* when there apparently are no free space in the heap to allocate new
* <code>Throwable</code> instance.
*
* <p>The test tries to occupy all of memory available in the heap by
* allocating lots of new <code>Object()</code> instances. Instances of the
* type <code>Object</code> are the smallest objects, so they apparently should
* occupy most fine-grained fragments in the heap and leave no free space for
* new <code>Throwable</code> instance. After that, the test provokes various
* exceptions (e.g.: by executing integer division by 0 and so on), and checks
* if appropriate exceptions are thrown.
*
* <p>Note, that memory occupation is terminated if memory allocation slows
* down crucially. This is a workaround intended to avoid the HotSpot bug:
* <br>
* #4248801 (P1/S5) slow memory allocation when heap is almost exhausted
*
* <p>There is also a workaround involved to avoid the following bugs known
* for HotSpot and for classic VM:
* <br>
* #4239841 (P1/S5) 1.1: poor garbage collector performance
* <br>
* #4245060 (P4/S5) poor garbage collector performance
* <br>However, printing of the test's error messages, warnings, and of
* execution trace may fail even so. If the test fails due to poor GC
* performance, exit status 96 is returned instead of 97.
*
* <p>Also note, that the test needs a lot of memory to start up, so it should
* not run under older JDK 1.1.x release due to its poor heap utilization.
*
* @author Eugene I. Latkin
*/
public class except004 {
/**
* Either allow or supress printing of execution trace.
*/
private static final boolean TRACE_ON = true; // false;
/**
* Either allow or supress printing of warning messages.
*/
private static final boolean WARN_ON = true;
/**
* Temporary <code>log</code> for error messages, warnings and/or execution
trace.
* @see #messages
*/
private static String log[] = new String [1000]; // up to 1000 messages
/**
* How many <code>messages</code> were submitted to the <code>log</code>.
* @see #log
*/
private static int messages = 0;
/**
* Re-call to the method <code>run(out)</code> (ignore <code>args[]</code>),
* and print the test summary - either test passed of failed.
*/
public static int run (String args[], PrintStream out) {
int exitCode;
try {
exitCode = run(out);
} catch (OutOfMemoryError oome) {
exitCode = 2;
log[messages++] = "java.lang.OutOfMemoryError in run(out)";
};
// Print the log[] and the test summary:
try {
for (int i=0; i<messages; i++)
out.println(log[i]);
if (exitCode == 0) {
if (TRACE_ON)
out.println("Test passed.");
} else
out.println("Test failed.");
} catch (OutOfMemoryError oome) {
// Poor performance of garbage collector:
exitCode = 1;
};
return exitCode;
};
/**
* Allocate as much <code>Object</code> instances as possible to bring JVM
* into stress, and then check if exceptions are correctly thrown accordingly
* to various situations like integer division by 0, etc.
*/
private static int run (PrintStream out) {
out.println("# While printing this message, JVM seems to initiate the
output");
out.println("# stream, so that it will not need more memory to print
later,");
out.println("# when the heap would fail to provide more memory.");
out.println("# ");
out.println("# Note, that the test maintains especial static log[] field
in");
out.println("# order to avoid printing when the heap seems exhausted.");
out.println("# Nevertheless, printing could arise OutOfMemoryError even");
out.println("# after all the memory allocated by the test is released.");
out.println("# ");
out.println("# That problem is caused by the known JDK/HotSpot bugs:");
out.println("# 4239841 (P1/S5) 1.1: poor garbage collector performance");
out.println("# 4245060 (P4/S5) poor garbage collector performance");
out.println("# ");
out.println("# This message is just intended to work-around that problem.");
out.println("# If printing should fail even so, the test will return the");
out.println("# exit status 96 instead of 97 to indicate the problem.");
// Prepare some items, which will be used by the test:
Object stringArray[] = new String [1];
Object integerValue = new Integer(0);
Object doubleValue = new Double(0);
Object trash = null;
Field abraPrivateField;
Field abraIntegerField;
Field abraBooleanField;
try {
abraPrivateField = Abra.class.getDeclaredField("DONT_TOUCH_ME");
abraIntegerField = Abra.class.getDeclaredField("MAIN_CYR_NUMBER");
abraBooleanField = Abra.class.getDeclaredField("NOT_AN_INTEGER");
} catch (NoSuchFieldException nsfe) {
out.println("Test initaition failed: field not found in class Abra");
return 2;
};
Abra abra = new Abra("via public constructor");
Abra.Cadabra cadabra = new Abra.Cadabra();
// Allocate repository for a lots of tiny objects:
Object pool[];
int poolSize = 1<<23; // ~8 millions
try {
pool = new Object [poolSize];
} catch (OutOfMemoryError oome) {
out.println("No enough memory to initiate the test.");
out.println("Test failed.");
return 2;
};
int index = 0;
// Sum up time spent, when it was hard to JVM to allocate next object
// (i.e.: when JVM has spent more than 1 second to allocate new object):
double totalDelay = 0;
long timeMark = System.currentTimeMillis();
try {
for (; index<poolSize; index++) {
//-------------------------
pool[index] = new Object();
long nextTimeMark = System.currentTimeMillis();
long elapsed = nextTimeMark - timeMark;
timeMark = nextTimeMark;
//----------------------
if (elapsed > 1000) {
double seconds = elapsed / 1000.0;
if (TRACE_ON)
out.println(
"pool[" + index + "]=new Object(); // elapsed " + seconds
+ "s");
totalDelay += seconds;
if (totalDelay > 60) {
if (TRACE_ON)
out.println(
"Memory allocation became slow; so, heap seems
exhausted.");
break;
};
};
};
} catch (OutOfMemoryError oome) {
if (TRACE_ON)
log[messages++] = "Heap seems exhausted - OutOfMemoryError thrown.";
// Do not release any byte once allocated:
pool[index++] = oome;
};
if (index > poolSize-1000) {
if (WARN_ON)
log[messages++] = "Warning: pool[] is full; so, checks would not be
enough hard...";
};
// Sum up exit code:
int exitCode=0; // apparently PASSED
int skipped=0; // some checks may correctly suffer OutOfMemoryError
// Check ArithmeticException:
try {
int x,y,z;
x = y = 0;
z = x / y;
log[messages++] = "Failure: ArithmeticException";
exitCode = 2; // FAILED
} catch (ArithmeticException ae) {
if (TRACE_ON)
log[messages++] = "Success: ArithmeticException";
pool[index++] = ae;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArithmeticException";
pool[index++] = oome;
skipped++;
};
/**************************************************************************/
try {
/***
*** Start proboscis block:
***/
// Check ArrayIndexOutOfBoundsException:
try {
pool[poolSize] = pool[index-1];
log[messages++] = "Failure: ArrayIndexOutOfBoundsException";
exitCode = 2; // FAILED
} catch (ArrayIndexOutOfBoundsException aioobe) {
/*A*/ if (TRACE_ON)
/*A*/ log[messages++] = "Success: ArrayIndexOutOfBoundsException";
pool[index++] = aioobe;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArrayIndexOutOfBoundsException";
pool[index++] = oome;
skipped++;
};
/***
*** Error is caught here:
***/
} catch (OutOfMemoryError oops) {
throw new RuntimeException("oops -- ArrayIndexOutOfBoundsException");
};
if (messages >= 0)
return 0;
/***************************************************************************/
// Check ArrayStoreException:
try {
stringArray[0] = integerValue;
log[messages++] = "Failure: ArrayStoreException";
exitCode = 2; // FAILED
} catch (ArrayStoreException ase) {
if (TRACE_ON)
log[messages++] = "Success: ArrayStoreException";
pool[index++] = ase;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ArrayStoreException";
pool[index++] = oome;
skipped++;
};
// Check ClassCastException:
try {
trash = (Double) integerValue;
log[messages++] = "Failure: ClassCastException";
exitCode = 2; // FAILED
} catch (ClassCastException cce) {
if (TRACE_ON)
log[messages++] = "Success: ClassCastException";
pool[index++] = cce;
} catch (OutOfMemoryError oome) {
if (WARN_ON)
log[messages++] = "Skipped: ClassCastException";
pool[index++] = oome;
skipped++;
};
// Check CloneNotSupportedException:
try {
trash = abra.clone(); // illegal - should fail
// trash = cadabra.clone(); // legal - should pass
log[message