2013-07-22 117 views
4

我的RMI应用程序出现问题。大约20小时后(+/-几个小时),客户端无法再连接。在服务器一生的前20个小时内,尽管我可以根据需要创建尽可能多的连接。我怀疑与RMI远程对象是garbacge收集有指向它的引用的一个问题,但我可以排除这种可能性有2个原因:为什么我的RMI服务器在20小时后死亡

  1. 我不得不运行在JVM服务器做使用jconsole一个GC并且客户端仍然可以连接
  2. 我在主方法中持有对我的服务器的引用,我不退出,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; 
} 



} 
+0

定义“无法再连接”。抛出什么异常? – EJP

+0

服务器上的任何错误?告诉我们你的日志。 –

+0

@stonedsquirrel在这个阶段,客户端的错误更加有趣。 – EJP

回答

1

main()循环是不是为了防止你的对象是DGC'd和GC'd的最佳途径。只需使stubregistry保持不变。

+0

@MarkoTopolnik你是错的。监听线程不会阻止垃圾收集。否则DGC和GC永远不会发生,而且他们会这样做。 – EJP

+0

@MarkoTopolnik(1)在说明书中,它说监听线程是否持有对该对象的硬引用? (在说明书中甚至会谈到一个监听线程?)如果你说的是真的,DGC怎么可能工作? (2)DGC关于分布式垃圾收集导出的远程对象。它不是关于任何事情*其他*实际上:*是*没有其他任何事情是关于它。 – EJP

+0

@MarkoTopolnik不,它不是。侦听端口的对象类型为'sun.rmi.transport.tcp.TCPTransport $ AcceptLoop.'导出的远程对象可以共享端口。例如,OP的代码可能已经为他的服务器和注册表使用了端口1099。尝试一下。如果你所说的是真的,那是不可能的。监听线程在导出的远程对象首次使用端口时启动,并在使用该端口的最后一个远程对象未导出时退出。你似乎只是在猜测。继续进行此交换之前,请查看源代码。 – EJP

相关问题