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

1.3: OutOfMemoryError thrown before finalizers run

XMLWordPrintable

    • gc
    • generic, sparc
    • generic, solaris_8



      Name: dkC59003 Date: 05/20/99



      When executing the test displayed below, HotSpot throws OutOfMemoryError
      due to poor performance of its garbage collector. Indeed, it likely should
      not throw OutOfMemoryError, when a small piece (~128Kb) of memory is requested,
      and there are tons (~40Mb) of unutilized garbage available in the heap.

      The following test tries to perform 50 cycles of allocation of all available
      memory and its deallocation. The hotspot's GC seems to fail to keep apace with
      actual memory operations, and the test usually fails after ~5th-15th cycle of
      memory allocation/deallocation. However, this test passes against classic VM
      (see details below).

      Note, that this test is inproper for compatibility testing; instead, it shows
      weakness of HotSpot's GC in comparision to classic GC:

      Classic VM execution is Ok:
          >>>> java -classic memleak001
          # invocations depth: 407
          # invocations depth: 406
          # invocations depth: 407
          # invocations depth: 407
          . . .
          # invocations depth: 406
          # invocations depth: 405
          # invocations depth: 404
          The test has PASSED.

      HotSpot execution fails:
          >>>> java memleak001
          # invocations depth: 477
          # invocations depth: 454
          # invocations depth: 23
          . . .
          # invocations depth: 454
          # invocations depth: 23
          # invocations depth: 477
          #
          # OOPS! Failed to allocate ~128Kb of memory while there
          # are tons (~40Mb) of unutilized garbage in the heap.
          #
          The test has FAILED.

      This test passes against JDK 1.0.2, 1.1.6, 1.2, 1.2.2, and 1.3 for Solaris/Sparc.

      This test passes against JDK 1.2, 1.2.2, and 1.3 for win32, if executed without JIT,
      or both with and without JIT if executed with the following command-line:
          java -classic memleak001
      However, the test fails against JDK 1.2, 1.2.2, and 1.3 for win32 having no HotSpot
      installed, if executed with JIT by the command-line:
          java memleak001

      This test passes against JDK 1.1.6 for windows both with JIT and without JIT.
      This test fails against JDK 1.0.2 for windows.

      All latest versions of HotSpot fail on this test:
          hotspot1_0rc1_hp-bin-solsparc-mar_12
          hotspot1_0fcs_hp-e-bin-win-apr_17
          hotspot2_0ea1_hp-a-bin-win-may_04
          hotspot_client1_3beta1_compiler1-d-bin-win-may_18

      Computers used to execute the test:
      1) SUNW Ultra-1, CPU UltraSPARC 167MHz, RAM 128Mb, SunOS 5.5.1
      2) Pentium-II 350MHz, RAM 128Mb, Windows NT 4.0 SP3, IE 4.01 SP1

      Below is the source of the test:
          ${TESTBASE_JS}/src/nsk/stress/memory/memleak001/memleak001.java:

      /* %W% %E%
       * Copyright %D% Sun Microsystems, Inc.
       */

      import java.io.PrintStream;

      /**
       * This test starts recursive procedure allocating a series of large
       * objects in order to exhaust JVM heap, and deletes all references
       * to those objects except of references found in invocations stack.
       *
       * <p>The test tries to provoke anticipatory finalization of those objects
       * by invoking System.runFinalization() when the recursive procedure
       * stops to go into deeper self-invocations. The test is treated passed,
       * if there is no finalization occurs of the objects just allocated
       * until that recursive procedure have return. (When that recursive
       * procedure returns, references to those objects are poped out from
       * the invocations stack, and their finalization becomes legal.)
       *
       * <p>This cycle of recursive memory allocation/deallocation is repeated
       * 50 times in order to test quality of the garbage collector. The test
       * must pass the first iteration of this cycle, but it may fail in later
       * iterations due to OutOfMemoryError, because garbage collector may do
       * not collect garbage after the first iteration of the cycle.
       *
       * <p>Indeed, JVM specification does not demand garbage collector to really
       * collect garbage, so that there may be no GC implemented at all! However,
       * I believe that every JVM pretending to be high-quality VM have to avoid
       * OutOfMemoryError when there are tons of garbage available in its heap.
       *
       * @author Eugene I. Latkin
       */
      public class memleak001 {
          static boolean testOver; // prohibit finalize()
          static int level; // shows recursion deeps
          
          static final int AMOUNT = 1 << 17; // 128Kb per piece
          static final int LIMIT = 1 << 10; // up to 128Mb total

          byte piece[]; // eat memory piece by piece
          
          memleak001 parent;
          memleak001 child = null;

          /**
           * Reference to <code>parent</code> should be used later
           * to clean parent's reference to this child instance.
           */
          public memleak001 (memleak001 parent, int amount) {
      this.parent = parent;
      piece = new byte [amount];
          };

          /**
           * Recursively incarnate a chain of <code>memleak001</code>
           * instances while <code>limit</code>&gt;1 and there is enough
           * memory to allocate new instances. Delete all references to
           * the allocated objects except of references kept in the
           * invocations stack, and try to provoke anticipatory
           * finalization of instances just incarnated.
           */
          void chain (int limit) {
      memleak001.level++;
          
      if (parent != null)
      parent.child = null;
      parent = null;

      try {
      if (limit > 1) {
      int amount = piece.length;
      child = new memleak001(this,amount);
      };
      } catch (OutOfMemoryError oome) {
      };

      if (child != null)
      try {
      child.chain(limit - 1);
      } catch (StackOverflowError error) {
      }
      else {
      System.runFinalization();
      testOver = true;
      };
          };
          
          /**
           * Reveal unexpected finalization.
           */
          public void finalize () {
      if (!testOver) {
      testOver = true; // error is revealed
      throw new MemLeak001Error(
      "Unexpected finalization of memleak001 instance, level="
      + level);
      };
          };
          
          /**
           * May be thrown only by <code>finalize()</code> method.
           */
          static class MemLeak001Error extends Error {
      MemLeak001Error (String purpose) {
      super(purpose);
      };
          };

          /**
           * Try to allocate a number of pieces of memory, so that
           * the only reference to each of those pieces should be found
           * in invocations stack. Assume the test is failed, if finalizer
           * tries to utilize those pieces before invocations stack have
           * poped-out references to them.
           */
          static int doRun (String args[], PrintStream out) {
      int amount = AMOUNT;
      if (args.length >= 1)
      amount = Integer.parseInt(args[0]);
      int limit = LIMIT;
      if (args.length >= 2)
      limit = Integer.parseInt(args[1]);

      level = 0;
      testOver = false;

      try {
      new memleak001(null,amount).chain(limit);

      } catch (OutOfMemoryError oome) {
      out.println("#");
      out.println("# OOPS! Failed to allocate ~128Kb of memory while there");
      out.println("# are tons (~40Mb) of unutilized garbage in the heap.");
      out.println("#");
      return 2;

      } catch (MemLeak001Error ml1e) {
      out.println("#");
      out.println("# " + ml1e);
      out.println("#");
      return 2;
      };

      if (level != 1)
      out.println("# invocations depth: " + level);

      return 0;
          };

          /**
           * Entry for JavaTest wrapper: return 0 if the test has passed,
           * and return 2 if the test has failed.
           */
          public static int run (String args[], PrintStream out) {
      int exitCode=0;

      for (int i=0; i<50; i++) {
      exitCode = doRun(args,System.out);
      if (exitCode != 0)
      break;
      System.gc();
      };

      if (exitCode == 0)
      System.out.println("The test has PASSED.");
      else
      System.out.println("The test has FAILED.");

      return exitCode;
          };

          /**
           * Exit code is 95 if the test passed, and 97 if the test
           * have failed (like JCK lang/vm tests).
           */
          public static void main (String args[]) {
      int exitCode = run(args,System.out);
      System.exit(exitCode + 95);
          };
      }

      ======================================================================

      Name: elR10090 Date: 03/22/2001



      Alexey Gibadullin, ###@###.###


      This bug also affects test from testbase_nsk:

          nsk/coverage/exceptionhandlertable/exceptionhandlertable001
          
      being executed against 64-bit Merlin-b56 on Solaris Sparc in all modes.
          
      ======================================================================

      Name: elR10090 Date: 09/26/2001


      Eugene I. Latkin <###@###.###>

      The "official" name of the test memleak001 is:
          nsk/stress/memory/memleak001

      I added this info here to help the script, which every day
      generates lists of known bugs for each of the testbase_nsk
      tests.

      Unfortunately, that script cannot recognize the test name
      embraced with suffix and/or prefix as:
          ${TESTBASE_JS}/src/nsk/stress/memory/memleak001/memleak001.java

      ======================================================================

            pbk Peter Kessler
            dkhukhrosunw Dmitry Khukhro (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: