Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-4264652

writing a constant into an array throws OutOfMemoryError

XMLWordPrintable

    • x86
    • windows_nt

      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>&nbsp;&nbsp;
       * #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>&nbsp;&nbsp;
       * #4239841 (P1/S5) 1.1: poor garbage collector performance
       * <br>&nbsp;&nbsp;
       * #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

            Unassigned Unassigned
            elatkinsunw Eugene Latkin (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: