I have a very simple RMI server that implements the UnicastRemoteObject. I have a main method that instantiates the server and binds it to the RMI registry. This is the only instance of the RMI server that is ever running. I have a remote client that looks up this server and calls one of the remote methods provided on the interface. Everything has been working fine until just recently the RMI server is being garbage collected. I implemented the unreferenced interface and added debug logging to the unreferenced method and to the finalize method. What I don't understand is how is the RMI server object becoming unreferenced when there is only one instance and it is referenced in the RMI registry. To solve my problem and keep the server from being garbage collected I added a call to rebind in the unreferenced method. This then updates the registry and keeps the server from being garbage collected. However, I am looking for ways to determine what could be causing the RMI registry to lose its reference to the server object. Anyone have ideas on ways to troubleshoot this problem? This is running on HP/UX 11i using JDK 1.3.x.
because the registry doesn't actually keep a reference to the server. It only keeps the information that a server using YourServerInterface should be located at some.ip.add.ress . It never holds a reference to your server object. You could just make your server runnable and use a timed loop in the run() method to keep it alive. Then it will always be there for your registry to point to until you specifically kill it by ending its timed loop. HTH Chris
Joined: Jun 20, 2003
Ok, I don't mean to disagree with you but I have found conflicting information in different news groups. A posting on the JGuru site indicates that the if a remote server is bound into the RMI registry that the unreferenced method for the remote object will never be called because the RMI registry is in fact holding a reference. Secondly, if it was true that the RMI registry does not hold some type of reference to the server instance then the fix I have currently coded would fail because the process of rebinding the server into the RMI registry would not add another reference to the server object and therefore the server object should be garbage collected. However the current coding of the unreferenced method to rebind to RMI registry does cause the server object to become referenced and therefore the server is no longer available for GC. Also, the bind method only accepts the string name and the server object. How would I pass an ip address and port for indicating the server location? The client applications are only aware of the rmi registry port and the ip address of the box, as well as the server name for look up. I have been able to force this situation by starting a second instance of the remote server and using the rebind method to bind the second instance over the first. When this happens the second instance is the server that will receive all client requests and the first instance will go unrefenced and be garbage collected. What I am trying to solve in production is could something like this be happening. I have changed all of the code to not allow a second instance to be started and bound into the RMI registry from the server code. But this does not keep some other process from performing a rebind or other action to remove the first instance. Are there any ways to debug when the bind or rebind methods are executed in the RMI Registry, short of writing my own registry?
Joined: Jun 27, 2000
Ah, a challenge! I accept! Challenges only help you refine your knowledge/beliefs. I'm gonna try to do my research on this one, so hold on, this may get crazy! To begin with, the poster on JGuru is wrong. Here's the what the java docs say about the unreferenced() method.
Called by the RMI runtime sometime after the runtime determines that the reference list, the list of clients referencing the remote object, becomes empty.
Since the registry is not a client, this method could be called any time there is no one connected. In addition to this, if there are no local references when the unreferenced() method is called, your server gets GC'd. Now, about the registry. It CAN'T hold a true reference to your server. References can only be held by objects operating in the same JVM. One way to run the registry is by starting it up from the JRE directories with a command line. But that would start it up in its own JVM, separate from your program's JVM. Thus, the registry can't be holding a true reference. I don't have the whole picture yet, but here is what I have gathered so far. Your server most likely extends UnicastRemoteObject. When a URO is instantiated, it exports itself somehow to be made available remotely through the RMI run-time system (this is not the registry, that comes later ). So any class that is coded to be aware of the RMI run-time system can actually return a link to your server through RMI. But I think it must be running on your local machine so that it can be aware of the local RMI situation. Now, the registry is one way to access the RMI info. There are others, and in fact, once you have access to the server itself, it can actually serve as a reference to other servers that might also be living on the same machine. Not sure exactly how that works, but i might try it some time. Back to the registry. While it doesn't hold a true reference to your server, it does hold a flat name key(there's no structure -file,web,nothing- its just a string) that it matches to a reference in the RMI system. This key is what you reference when you do a Naming.lookup() in your client. The RMI refence returned by a lookup can then be accessed directly by the client without going through the registry. Whew its getting late. I've been researching this for about 3 hours. I hope I've made at least a little sense. Please ask questions if you have them. I learn a whole lot more about how things work when I have to explain them to others. Chris
Joined: Jun 27, 2000
Oops forgot to answer a couple of your other questions. 1)
Also, the bind method only accepts the string name and the server object. How would I pass an ip address and port for indicating the server location? The client applications are only aware of the rmi registry port and the ip address of the box, as well as the server name for look up.
you can't. The bind/rebind string you use is a flat string and doesn't get parsed for any kind of structure. But you don't need structure anyways. The client has everything it needs to access the registry which should know about any servers which are bound to it. 2)
I have been able to force this situation by starting a second instance of the remote server and using the rebind method to bind the second instance over the first. When this happens the second instance is the server that will receive all client requests and the first instance will go unrefenced and be garbage collected.
yep, see my explanation in the other post. unreferenced() gets called and no local references held, then *poof* -GC'd 3)
But this does not keep some other process from performing a rebind or other action to remove the first instance. Are there any ways to debug when the bind or rebind methods are executed in the RMI Registry, short of writing my own registry?
Any rebind using the same string will *rebind* over the old one. You can of course, bind different interface types without overbinding by using a different string name. You can also bind the same server into the registry more than once by using different name strings. HTH Chris edited to take out some incorrect stuff I typed last night. I wasn't thinking straight. [ April 02, 2004: Message edited by: Chris Shepherd ]