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

Inconsistent/Incomplete Garbage-Collection Behavior

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Not an Issue
    • Icon: P3 P3
    • None
    • 1.1.4
    • hotspot
    • None
    • x86
    • windows_95



      Name: sg39081 Date: 10/21/97


      The following simple Java applications
      demonstrate unusual, unexpected behavior
      involving garbage collection. I wonder if this
      behavior reveals the presence of bug(s) in Java.
      I have included the Java source code, as well as
      the output I get from each program. I am running
      Win NT 4.0 on a Pentium Pro 200, with JDK 1.1.4.

      MemoryTest1: The baseline, or "control", test.
      Garbage-collection proceeds as expected.

      MemoryTest2: Unusual behavior is produced,
      if the code examines the args[] parameter as part
      of a conditional expression.

      MemoryTest3: Unusual behavior is produced,
      if the code calls a do-nothing method of the
      'Test' class.

      For tests 2 and 3, normal behavior can be
      restored by commenting out the indicated line(s)
      of code. See the source code for details.

      I am interested in feedback, especially from
      JavaSoft. Is this a bug in Java? Or do I
      misunderstand garbage collection? Although these
      examples may seem pedantic, they are simplified
      versions of similar problems we are encountering
      in our large-scale Java Application development
      effort.

      Note: these are applications, not applets.
      See the console output, below, for the
      command-lines used to run these applications.

      ---Console Output---
      C:\TEMP>javac MemoryTest1.java

      C:\TEMP>java MemoryTest1
      Both objects will be finalized, as expected.
      (Even though none of the object references are re-assigned to null.)
      'Test 1' constructed.
      'Test 2' constructed.
      'Test 1' finalized.
      'Test 2' finalized.

      C:\TEMP>javac MemoryTest2.java

      C:\TEMP>java MemoryTest2 yes
      Both objects will be finalized, as expected, IF the command-line argument is
      'yes'.
      BUT only one object will be finalized, IF the command-line argument is 'no'.
      (This is unexpected behavior -- compare to results from MemoryTest1.)
      'Test 1' constructed.
      'Test 2' constructed.
      Nullifying reference to 'Test 1'.
      'Test 1' finalized.
      'Test 2' finalized.

      C:\TEMP>java MemoryTest2 no
      Both objects will be finalized, as expected, IF the command-line argument is
      'yes'.
      BUT only one object will be finalized, IF the command-line argument is 'no'.
      (This is unexpected behavior -- compare to results from MemoryTest1.)
      'Test 1' constructed.
      'Test 2' constructed.
      'Test 2' finalized.

      C:\TEMP>javac MemoryTest3.java

      C:\TEMP>java MemoryTest3
      ONLY ONE object will be finalized.
      (This is unexpected behavior -- compare to results from MemoryTest1.)
      'Object 1' constructed.
      'Object 2' constructed.
      Nullifying reference to 'Object 1'.
      'Object 1' finalized.

      C:\TEMP>

      ---MemoryTest1 Source Code---

      public class MemoryTest1
      {
      public static void main(String args[])
      {
      System.out.println("Both objects will be finalized, as
      expected.");
      System.out.println("(Even though none of the object references
      are re-assigned to null.)");
      MyObject obj1 = new MyObject("Test 1");
      MyObject obj2 = new MyObject("Test 2");
      System.gc();
      System.runFinalization();
      }
      }

      class MyObject
      {
      String label;

      MyObject(String label)
      {
      this.label = label;
      System.out.println("'" + label + "' constructed.");
      }

      protected void finalize() throws Throwable
      {
      super.finalize();
      System.out.println("'" + label + "' finalized.");
      }
      }

      ---MemoryTest2 Source Code---

      public class MemoryTest2
      {
      public static void main(String args[])
      {
      System.out.println("Both objects will be finalized, as expected,
      IF the command-line argument is 'yes'.");
      System.out.println("BUT only one object will be finalized, IF
      the command-line argument is 'no'.");
      System.out.println("(This is unexpected behavior -- compare to
      results from MemoryTest1.)");
      MyObject obj1 = new MyObject("Test 1");
      MyObject obj2 = new MyObject("Test 2");

      /* switch the "ifs", below, to yield different behavior */

      //if (true) { /*
      this "if" yields expected behavior */
      if (args.length > 0 && args[0].equalsIgnoreCase("yes")) { /*
      this "if" triggers the unexpected behavior */
      System.out.println("Nullifying reference to 'Test 1'.");
      obj1 = null;
      }

      System.gc();
      System.runFinalization();
      }
      }

      class MyObject
      {
      String label;

      MyObject(String label)
      {
      this.label = label;
      System.out.println("'" + label + "' constructed.");
      }

      protected void finalize() throws Throwable
      {
      super.finalize();
      System.out.println("'" + label + "' finalized.");
      }
      }

      ---MemoryTest3 Source Code---

      public class MemoryTest3
      {
      public static void main(String args[])
      {
      System.out.println("ONLY ONE object will be finalized.");
      System.out.println("(This is unexpected behavior -- compare to
      results from MemoryTest1.)");
      Test t = new Test();

      // this call to this 'dummy' method triggers the unexpected
      behavior.
      // comment out this call, and both objects should get finalized.
      t.dummy();

      System.gc();
      System.runFinalization();
      }
      }

      class Test
      {
      MyObject c1;
      MyObject c2;

      Test()
      {
      c1 = new MyObject("Object 1");
      c2 = new MyObject("Object 2");
      System.out.println("Nullifying reference to 'Object 1'.");
      c1 = null;
      }

      void dummy()
      {
      }

      }

      class MyObject
      {
      String label;

      MyObject(String label)
      {
      this.label = label;
      System.out.println("'" + label + "' constructed.");
      }

      protected void finalize() throws Throwable
      {
      super.finalize();
      System.out.println("'" + label + "' finalized.");
      }
      }
      ======================================================================

            apalanissunw Anand Palaniswamy (Inactive)
            sgoodsunw Sheri Good (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: