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

RMI unexportObject stops garbage collection

XMLWordPrintable

    • Icon: Bug Bug
    • Resolution: Duplicate
    • Icon: P4 P4
    • None
    • 1.3.0
    • core-libs
    • sparc
    • solaris_8



      Name: skT45625 Date: 06/16/2000


      java version "1.3.0"
      Java(TM) 2 Runtime Environment, Standard Edition (build 1.3.0-beta)
      Java HotSpot(TM) Client VM (build 1.3-beta, mixed mode)

      Calling UnicastRemoteObject.unexportObject seems to stop garbage
      collection of a remote object.

      The attached code demonstrates the problem.
      This was re-tested with the latest 1.3 beta release.
      It consists of remote Client/Server programs running using RMI.
      The Server supplies Dummy remote objects to a client
      (using the Factory interface). It periodically creates and deletes
      remote Dummy objects. Every cycle the existing remote object is
      unexported, the reference released, and a new Dummy object created.
      Garbage collection is explicitly run every cycle.
      A list is kept of all Dummy objects that have not yet been finalized
      in the Server. This is printed whenever that list changes.

      The Client periodically connects to the remote Server to obtain
      a remote Dummy object and then get an integer value from it.
      The reference to that remote object is then released.
      Garbage collection is explicitly performed each 20 cycles
      so that remote references do not accumulate.

      When the Server is executed, Dummy objects are correctly garbage
      collected. When the Client begins running, Dummy remote objects
      continually accumulate in the Server until OutOfMemoryError exception
      occurs. To force this to fail faster, the Server was run with a limit
      of 5M heap. Leasing and lease expiry was set to 10sec to ensure
      that remote references were garbage collected quickly.

      The following commands were used to build and run the programs:

      > javac *.java
      > rmic -v1.2 DummyImpl
      > rmic -v1.2 Server
      > rmiregistry &
      > java -Xmx5m -Djava.rmi.dgc.leaseValue=10000 -Dsun.rmi.dgc.checkInterval=10000
      Server &
      > java -verbose:gc Client


      If Server.java is modified to remove the call to unexportObject and
      the programs are re-run, Dummy remote objects are garbage collected
      and the program runs indefinitely.

      The unexportObject call (marked with ### in the code) appears to
      stop remote objects from being garbage collected while the client
      is running even though the remote references have been garbage collected
      in the client.




      ------------------------------------------ file Client.java
      import java.rmi.*;

      /**
       * Client periodically connects to a remote factory to obtain
       * a remote dummy object and then get an integer value from it.
       * The reference to that remote object is then released.
       * Garbage collection is explicitly performed each
       * 20 cycles so that remote references do not accumulate.
       */
      class Client
      {
          private Factory factory = null;
          private int count = 0;

          public Client()
          {
      try {
      factory = (Factory)Naming.lookup("Factory");
      } catch (Exception e) {
      System.err.println("Cannot get factory.");
      System.err.println(e.getMessage());
      e.printStackTrace();
      }
      Thread cycle = new Cycle();
      cycle.start();
          }

          // Method executed periodically
          public void test()
          {
      try {
      // Get remote dummy object
      Dummy dummy = factory.getDummy();
      if (dummy != null) {
      int value = dummy.getValue();
      System.out.println("Dummy value = " + value);
      }

      // Ensure remote dummy objects are garbage collected.
      dummy = null;
                  if (++count >= 20) {
      System.gc();
      count = 0;
                  }
      } catch (Exception e) {
      // Occasional errors expected due to dummy object
      // not existing in server.
      System.err.println("Error when testing dummy." + e.getMessage());
      e.printStackTrace();
      }
          }

          class Cycle extends Thread
          {
      public void run()
      {
      while (true) {
      test();
      try {
      sleep(300);
      } catch (InterruptedException e) {}
      }
      }
          }

          public static void main(String[] args)
          {
      new Client();
          }
      }

      ------------------------------------------ file Dummy.java
      import java.rmi.*;

      /**
       * A remote object just for test purposes.
       */
      interface Dummy extends Remote
      {
          int getValue() throws RemoteException;
      }

      ------------------------------------------ file DummyImpl.java
      import java.rmi.*;
      import java.rmi.server.*;
      import java.util.*;

      /**
       * A dummy remote object that supplies an integer value.
       * A list is kept of all objects that have not yet been finalized.
       */
      class DummyImpl extends UnicastRemoteObject implements Dummy
      {
          private static List values =
      Collections.synchronizedList(new LinkedList());

          private int value = 0;
          private int[] data = null;
          
          public DummyImpl(int value) throws RemoteException
          {
      super();
      this.value = value;
      values.add(new Integer(value));
      printValues();
      // grab a chunk of memory to stress gc.
      data = new int[50000];
          }

          public int getValue()
          {
      return value;
          }

          /**
           * Print a list of all dummy objects that have not
           * yet been finalized.
           */
          public void printValues()
          {
      synchronized(values) {
      if (!values.isEmpty()) {
      Iterator iter = values.iterator();
      while (iter.hasNext()) {
      Integer val = (Integer)iter.next();
      System.out.print(val + " ");
      }
      System.out.println();
      }
      }
          }

          /**
           * Keep track of all objects that have not been finalized.
           */
          protected void finalize() throws Throwable
          {
      super.finalize();
      values.remove(new Integer(value));
      printValues();
          }
      }

      ------------------------------------------ file Factory.java
      import java.rmi.*;

      /**
       * Factory to supply dummy objects to a client.
       */
      interface Factory extends Remote
      {
          Dummy getDummy() throws RemoteException;
      }

      ------------------------------------------ file Server.java
      import java.rmi.*;
      import java.rmi.server.*;

      /**
       * Main server program that periodically creates and deletes
       * remote dummy objects. Every cycle the existing remote
       * object is unexported, the reference released, and a new
       * dummy object created. Garbage collection is explicitly
       * run every cycle.
       */
      class Server extends UnicastRemoteObject implements Factory
      {
          private Dummy dummy = null;
          private int counter = 0;

          public Server() throws RemoteException
          {
      super();
      Thread cycle = new Cycle();
      cycle.start();
          }

          public synchronized Dummy getDummy() throws RemoteException
          {
      return dummy;
          }

          /**
           * Create a new remote object that can be obtained
           * through the factory.
           */
          public synchronized void createDummy()
          {
      try {
      dummy = new DummyImpl(++counter);
      } catch (Exception e) {
      System.err.println("Error creating dummy. " + e.getMessage());
      e.printStackTrace();
      }
          }

          /**
           * Unexport the current dummy object and release it's reference.
           * Explicitly run garbage collection so that objects do not
           * accumulate.
           */
          public synchronized void deleteDummy()
          {
      if (dummy != null) {
      try {
      // ### This causes problems
      UnicastRemoteObject.unexportObject(dummy, false);
      } catch (Exception e) {
      System.err.println("Error deleting dummy. " + e.getMessage());
      }
      dummy = null;
      }
      System.gc();
          }

          class Cycle extends Thread
          {
      public void run() {
      while (true) {
      createDummy();
      try {
      sleep(1000);
      } catch (InterruptedException e) {}
      deleteDummy();
      }
      }
          }

          public static void main(String[] args)
          {
      try {
      Factory factory = new Server();
      Naming.rebind("Factory", factory);
      } catch (Exception e) {
      System.err.println("Error testing Server." + e.getMessage());
      }
          }
      }
      (Review ID: 106174)
      ======================================================================

            awollratsunw Ann Wollrath (Inactive)
            skondamasunw Suresh Kondamareddy (Inactive)
            Votes:
            0 Vote for this issue
            Watchers:
            0 Start watching this issue

              Created:
              Updated:
              Resolved:
              Imported:
              Indexed: