Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p><strong>Keep a strong reference to the object that implements the <code>java.rmi.Remote</code> interface so that it remains <a href="http://java.sun.com/docs/books/jls/third_edition/html/execution.html#12.6.1" rel="noreferrer">reachable</a>, i.e. ineligible for garbage collection.</strong></p> <p>Below is a short program that demonstrates a <a href="http://java.sun.com/javase/6/docs/api/java/rmi/NoSuchObjectException.html" rel="noreferrer"><code>java.rmi.NoSuchObjectException</code></a>. The script is self-contained, creating an RMI registry as well as a "client" and a "server" in a single JVM.</p> <p>Simply copy this code and save it in a file named <code>RMITest.java</code>. Compile and invoke with your choice of command line arguments:</p> <ul> <li><strong><code>-gc</code></strong> (default) Explicitly instruct the JVM to make "a best effort" to run the garbage collector after the server is started, but before the client connects to the server. This will likely cause the <code>Remote</code> object to be reclaimed by the garbage collector <em>if the strong reference to the <code>Remote</code> object is <strong>released</em></strong>. A <code>java.rmi.NoSuchObjectException</code> is observed when the client connects after the <code>Remote</code> object is reclaimed.</li> <li><strong><code>-nogc</code></strong> Do not explicitly request garbage collection. This will likely cause the <code>Remote</code> object to remain accessible by the client regardless of whether a strong reference is held or released <em>unless there is a sufficient <strong>delay</strong> between the server start and the client call such that the system "naturally" invokes the garbage collector and reclaims the <code>Remote</code> object</em>.</li> <li><strong><code>-hold</code></strong> Retain a strong reference to the <code>Remote</code> object. In this case, a class variable refers to the <code>Remote</code> object.</li> <li><strong><code>-release</code></strong> (default) A strong reference to the <code>Remote</code> object will be released. In this case, a method variable refers to the <code>Remote</code> object. After the method returns, the strong reference is lost.</li> <li><strong><code>-delay&lt;S&gt;</code></strong> The number of seconds to wait between server start and the client call. Inserting a delay provides time for the garbage collector to run "naturally." This simulates a process that "works" initially, but fails after some significant time has passed. Note there is no space before the number of seconds. Example: <code>-delay5</code> will make the client call 5 seconds after the server is started.</li> </ul> <p>Program behavior will likely vary from machine to machine and JVM to JVM because things like <code>System.gc()</code> are only hints and setting the <code>-delay&lt;S&gt;</code> option is a guessing game with respect to the behavior of the garbage collector.</p> <p>On my machine, after <code>javac RMITest.java</code> to compile, I see this behavior:</p> <pre><code>$ java RMITest -nogc -hold received: foo $ java RMITest -nogc -release received: foo $ java RMITest -gc -hold received: foo $ java RMITest -gc -release Exception in thread "main" java.rmi.NoSuchObjectException: no such object in table at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255) at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233) at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142) at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178) at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132) at $Proxy0.remoteOperation(Unknown Source) at RMITest.client(RMITest.java:69) at RMITest.main(RMITest.java:46) </code></pre> <p>Here is the source code:</p> <pre><code>import java.rmi.Remote; import java.rmi.RemoteException; import java.rmi.registry.LocateRegistry; import java.rmi.registry.Registry; import java.rmi.server.UnicastRemoteObject; import static java.util.concurrent.TimeUnit.*; interface RemoteOperations extends Remote { String remoteOperation() throws RemoteException; } public final class RMITest implements RemoteOperations { private static final String REMOTE_NAME = RemoteOperations.class.getName(); private static final RemoteOperations classVariable = new RMITest(); private static boolean holdStrongReference = false; private static boolean invokeGarbageCollector = true; private static int delay = 0; public static void main(final String... args) throws Exception { for (final String arg : args) { if ("-gc".equals(arg)) { invokeGarbageCollector = true; } else if ("-nogc".equals(arg)) { invokeGarbageCollector = false; } else if ("-hold".equals(arg)) { holdStrongReference = true; } else if ("-release".equals(arg)) { holdStrongReference = false; } else if (arg.startsWith("-delay")) { delay = Integer.parseInt(arg.substring("-delay".length())); } else { System.err.println("usage: javac RMITest.java &amp;&amp; java RMITest [-gc] [-nogc] [-hold] [-release] [-delay&lt;seconds&gt;]"); System.exit(1); } } server(); if (invokeGarbageCollector) { System.gc(); } if (delay &gt; 0) { System.out.println("delaying " + delay + " seconds"); final long milliseconds = MILLISECONDS.convert(delay, SECONDS); Thread.sleep(milliseconds); } client(); System.exit(0); // stop RMI server thread } @Override public String remoteOperation() { return "foo"; } private static void server() throws Exception { // This reference is eligible for GC after this method returns final RemoteOperations methodVariable = new RMITest(); final RemoteOperations toBeStubbed = holdStrongReference ? classVariable : methodVariable; final Remote remote = UnicastRemoteObject.exportObject(toBeStubbed, 0); final Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT); registry.bind(REMOTE_NAME, remote); } private static void client() throws Exception { final Registry registry = LocateRegistry.getRegistry(); final Remote remote = registry.lookup(REMOTE_NAME); final RemoteOperations stub = RemoteOperations.class.cast(remote); final String message = stub.remoteOperation(); System.out.println("received: " + message); } } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload