RMI server shuts down on its own RMI server shuts down on its own multithreading multithreading

RMI server shuts down on its own


You're seeing an interaction of the VM exiting when its last non-daemon thread exits, combined with HotSpot garbage collection behavior, RMI's exporting behavior, and running the JVM under the NetBeans profiler.

The main thread exits after the main() method returns. However, you've exported an RMI server object, so RMI keeps the JVM alive by running the "RMI Reaper" thread (non-daemon) as long as there are live, exported objects. RMI determines whether an exported object is "alive" by keeping only a weak reference to it in it object table.

Unfortunately, from looking at the main() method, it appears that your RMI server object is only referenced via local variables. Thus, it will get garbage collected sooner or later, but for the weak reference to it in RMI's object table. When the object becomes weakly reachable, the RMI Reaper unexports it and exits. Since the RMI Reaper is the last non-daemon thread, the JVM exits.

Note that the RMI registry is treated specially. Exporting a registry will not keep a JVM alive.

Note also that putting an infinite loop at the end of the main() method will not necessarily prevent the RMI server object from being unexported and GC'd. The reason is that objects are subject to GC when they become unreachable, and a reference being present in a local variable of an active method is not sufficient to make it reachable. See my answer to another question on that topic. Of course, putting an infinite loop into main() will prevent the JVM from exiting, since it keeps the main thread alive, and the main thread is not a daemon thread.

To prevent your RMI server from being unexported, it's usually sufficient to store a reference to it in a static field.

Now, why does the JVM stick around when run under the profiler? That's just an artifact of the way the profiler works. The profiler detects that the last non-daemon thread has exited (other than additional threads running in the JVM on behalf of the profiler), so that's when it pops up the dialog that says "The profiled application has finished execution." It keeps the JVM alive, though, so you can continue to get data from it; this has the side effect keeping all the daemon threads alive. You've exported a registry, so that keeps listening on port 1099. When the JVM is in this state you might still be able to register RMI objects if you tried. Your RMI server object has long since been unexported and GC'd, so requests to it won't work. But that's why the RMI connection was still accepted when the JVM was in this state.

Bottom line is, make sure your RMI server objects don't get GC'd. A good way to do this is to make sure they're reachable from a static field.


This is a common problem with RMI. You need to save the reference to your implementation as a class field so it doesn't get GC. And you need to keep that class (with the main()) alive as well.

I use this as a never-ending keep alive:

for(;;) LockSupport.park(); 

You can do anything you like so the implementation remains alive and the class with the main() stays alive.