我的 RMI 应用程序有问题。大约 20 小时(+/- 几小时)后,客户端无法再连接。在服务器生命周期的前 20 小时内,尽管我可以建立任意数量的连接。我怀疑 RMI 远程对象被垃圾收集存在问题,因为没有指向它的引用,但我可以排除这两个原因:
- 我强制运行服务器的 JVM 使用 jconsole 进行 GC,客户端仍然可以连接
- 我在 main 方法中持有对我的服务器的引用,我不会退出该方法,并且 RMI 注册表和存根是我的服务器类的成员。
我的服务器在端口 1099 上创建了一个 RMI 注册表,并在端口 5099 上导出为 UnicastRemoteObject。当客户端在 20 小时后无法再连接时,我得到一个 java.rmi.ConnectException。需要明确的是,服务器的 java 进程仍在运行,并且注册表(在该进程中运行)仍在响应并返回远程对象。当我在客户端调用远程方法时引发异常。
如果我在我的服务器机器上执行“netstat -tulpn”,我可以看到 Java 进程最初正在侦听端口 5099,但是一旦 20 小时的错误在服务器中启动,就不再在该端口上侦听。我想我也可以排除防火墙问题,因为我已禁用服务器防火墙进行测试。下面是我的代码的简化版本。任何关于那里发生的事情以及如何使服务器无限期运行的想法将不胜感激。干杯!
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
public class MyRMIServer implements MyRMIInterface {
private MyRMIInterface stub;
private Registry registry;
public static void main(String[] args)
{
MyRMIServer server = new MyRMIServer();
server.startRmiServices();
// now sleep, don't let the main thread die, otherwise we might loose our ref to the
// RMI stub and/or registry
while (true)
{
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
private void startRmiServices()
{
try {
// set up security manager
if (System.getSecurityManager() == null) {
System.setSecurityManager(new SecurityManager());
}
// create stub
stub = (MyRMIInterface) UnicastRemoteObject.exportObject(this,5099);
// Bind the remote object's stub in the registry
registry = LocateRegistry.createRegistry(1099);
registry.rebind("MyServer", stub);
System.out.println("RMI ready");
} catch (RemoteException e) {
e.printStackTrace();
}
}
@Override
public synchronized int remoteCall(int x) throws RemoteException
{
return x+1;
}
}