/* * Copyright (c) 1999, 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. */ /* * @test * @key stress * * @summary converted from VM testbase nsk/stress/except/except001. * VM testbase keywords: [stress, diehard, slow, nonconcurrent, quick] * VM testbase readme: * DESCRIPTION * This checks if OutOfMemoryError exception is correctly enwrapped into * InvocationTargetException when thrown inside a method invoked via * reflection. * The test tries to occupy all of memory available in the heap by * allocating lots of new Object() instances. Instances of the "empty" * type Object are the smallest objects, so they apparently should occupy * most fine-grained fragments in the heap. Thus, there apparently should * not remain any free space to incarnate new Throwable instance, and VM * possibly could crash while trying to throw new OutOfMemoryError and * enwrap it into new InvocationTargetException instance. * By the way, the test checks time elapsed to allocate memory. Both * classic VM and HotSpot seem to fall into poor performance of memory * allocation when heap is almost over. E.g.: HotSpot 1.3-betaH may spend * more than 1 minute to allocate next Object in this case (tested on * Pentium-II, 350MHz, 128Mb RAM). To avoid this problem, the test enforce * OutOfMemoryError if more then 5 minutes is spent to allocate "last bytes" * of memory. * COMMENTS * HotSpot releases 1.0-fcsE (both Win32 and Sparc), and 1.3-betaH (Win32) * fail on this test due to poor performance of memory allocation. * #4248801 (P3/S5) slow memory allocation when heap is almost exhausted * Despite this bug is treated fixed in HotSpot 1.0.1, it still does suffer * slow memory allocation when running on PC having 64Mb or less of RAM. * There is also a workaround involved to avoid the following bugs known * for HotSpot and for classic VM: * #4239841 (P1/S5) 1.1: poor garbage collector performance (HotSpot bug) * #4245060 (P4/S5) poor garbage collector performance (Classic VM bug) * However, printing of the test's error messages, warnings, and of execution * trace may fail under JDK 1.2 for Win32 even so. * HotSpot 2.0-devA (Win32) crashes due to the known HotSpot bug: * #4239828 (P1/S4) 1.3c1: VM crashes when heap is exhausted * * @run main/othervm -Xms50M -Xmx200M nsk.stress.except.except001 */ package nsk.stress.except; import java.io.PrintStream; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * This checks if OutOfMemoryError exception is correctly * enwrapped into InvocationTargetException when thrown inside * a method invoked via reflection. *

*

The test tries to occupy all of memory available in the heap by * allocating lots of new Object() instances. Instances of the * ``empty'' type Object are the smallest objects, so they * apparently should occupy most fine-grained fragments in the heap. * Thus, there apparently should not remain any free space to incarnate new * Throwable instance, and VM possibly could crash while trying * to throw new OutOfMemoryError and enwrap it into new * InvocationTargetException instance. *

*

By the way, the test checks time elapsed to allocate memory. * Both classic VM and HotSpot seem to fall into poor performance of memory * allocation when heap is almost over. E.g.: HotSpot 1.3-betaH may spend * more than 1 minute to allocate next Object in this case * (tested on Pentium-II, 350MHz, 128Mb RAM). To workaround this problem, * the test enforces OutOfMemoryError if more then 5 minutes * is spent to allocate ``last bytes'' of the memory. */ public class except001 { /** * This field allows or supresses printing with display() * method. * * @see #display(Object) * @see #complain(Object) * @see #out */ private static boolean MODE_VERBOSE = true; /* * Storage for a lot of tiny objects * "static volatile" keywords are for preventing heap optimization */ private static volatile Object pool[] = null; /** * Print execution trace if MODE_VERBOSE is true * (optional). * * @see #MODE_VERBOSE * @see #complain(Object) * @see #out */ private static void display(Object message) { if (MODE_VERBOSE) out.println(message.toString()); out.flush(); } /** * Print error message. * * @see #display(Object) * @see #out */ private static void complain(Object message) { out.println("# " + message); out.flush(); } /** * The log-stream assigned at runtime by the method * run(args,out). * * @see #display(Object) * @see #complain(Object) * @see #run(String[], PrintStream) */ private static PrintStream out; /** * Try to allocate lots of instances of the type Object. * Such instances are most fine-grained, and thus they should occupy * smallest fragments of free memory in the heap. *

*

By the way, break the test, if JVM has spent more than * 5 minutes to allocate latest portions of memory. */ public static void raiseOutOfMemory() throws OutOfMemoryError { try { // Repository for objects, which should be allocated: int index = 0; for (int size = 1 << 30; size > 0 && pool == null; size >>= 1) try { pool = new Object[size]; } catch (OutOfMemoryError oome) { } if (pool == null) throw new Error("HS bug: cannot allocate new Object[1]"); // 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(); for (; index < pool.length; index++) { //------------------------- pool[index] = new Object(); long nextTimeMark = System.currentTimeMillis(); long elapsed = nextTimeMark - timeMark; timeMark = nextTimeMark; //---------------------- if (elapsed > 1000) { double seconds = elapsed / 1000.0; display( "pool[" + index + "]=new Object(); // elapsed " + seconds + "s"); totalDelay += seconds; if (totalDelay > 300) { complain( "Memory allocation became slow: so heap seems exhausted."); throw new OutOfMemoryError(); } } } // This method should never return: throw new Error("TEST_BUG: failed to provoke OutOfMemoryError"); } finally { // Make sure there will be enough memory for next object allocation pool = null; } } /** * Invoke the method raiseOutOfMemory() with reflection, * and check if the exception it throws is just * OutOfMemoryError enwrapped into * InvocationTargetException instance. *

*

Before the test begins, this.out filed is assigned * to the parameter out. Parameter args[] * is ignored. * * @see #raiseOutOfMemory() */ public static int run(String args[], 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("# 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."); if (args.length > 0) { if (args[0].toLowerCase().startsWith("-v")) MODE_VERBOSE = true; } except001.out = out; Class testClass = except001.class; try { Method testMethod = testClass.getMethod("raiseOutOfMemory", new Class [0]); Object junk = testMethod.invoke(null, new Object [0]); } catch (InvocationTargetException ite) { Throwable targetException = ite.getTargetException(); if (targetException instanceof OutOfMemoryError) { display("OutOfMemoryError thrown as expected."); display("Test passed."); return 0; } complain("Unexpected InvocationTargetException: " + targetException); complain("Test failed."); return 2; } catch (Exception exception) { complain("Unexpected exception: " + exception); complain("Test failed."); return 2; } // complain("The test has finished unexpectedly."); complain("Test failed."); return 2; } /** * Re-call to run(args,out), and return JCK-like exit status. * (The stream out is assigned to System.out here.) * * @see #run(String[], PrintStream) */ public static void main(String args[]) { Thread.currentThread().setUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() { // Last try. If there is some exception outside the code, test should end correctly @Override public void uncaughtException(Thread t, Throwable e) { try { pool = null; System.gc(); if (e instanceof OutOfMemoryError) { try { System.out.println("OOME : Test Skipped"); System.exit(95); } catch (Throwable ignore) { } // No code in the handler can provoke correct exceptions. } else { e.printStackTrace(); throw (RuntimeException) e; } } catch (OutOfMemoryError oome) { } } }); int exitCode = run(args, System.out); System.exit(exitCode + 95); // JCK-like exit status. } }