在尝试使用 RMI 时,我遇到了一个 java.rmi.NoSuchObjectException
异常,这让我想到了这个问题:java.rmi.NoSuchObjectException: no such object in table 但我的问题不同。
我在我的 main 方法中创建了 impl 对象,因此在主线程中。如果我这样做:
FooImpl fi = new FooImpl();
foo = (Foo) UnicastRemoteObject.exportObject(fi, 0);
一切正常。
如果我这样做:
foo = (Foo) UnicastRemoteObject.exportObject(new FooImpl(), 0);
我看到收集了 FooImpl 实例,然后我得到了上述异常。
foo
是我在 main 中初始化的静态引用;另一个远程对象从它的一个方法返回 foo
。因此,客户端首先获取该远程对象,然后从中获取 foo
,然后调用 foo
上的方法,这就是我收到上述异常的时间。那么为什么会这样呢?
编辑:这是我的主要方法
public static void main(String[] args) throws RemoteException, AlreadyBoundException
{
Server server = new Server();
Hello stub = (Hello) UnicastRemoteObject.exportObject(server, 0);
FooImpl fi = new FooImpl();
foo = (Foo) UnicastRemoteObject.exportObject(fi, 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Hello", stub);
System.out.println("Server ready!");
}
在客户端中,我得到了 hello
并在其上调用了一个方法,该方法为我提供了 foo
,然后在 foo
上调用了一个方法。
EDIT2:如果我使用
Hello stub = (Hello) UnicastRemoteObject.exportObject(new Server(), 0);
并首先绑定(bind) foo
,然后绑定(bind) hello
,然后当我尝试访问 hello
时会抛出相同的异常,因为现在它是 Server 实例收集起来。真是奇怪的东西!
最佳答案
这两种方法都可能失败。它们在变量作用域方面没有真正的区别。
在这些情况下更常见的问题是注册表本身,当由 LocateRegistry.createRegistry()
创建时,您并没有这样做。如果是,则创建的注册表本身也可以被 GC:您必须将 Registry
引用保存在静态变量中。然后它将不会被 GC,并且它将阻止 stub foo
被 GC,并且 stub 将阻止 FooImpl
被 DGC,并且因此 GC。
在您的情况下,最好将远程对象引用(服务器,而不是 stub )保存在静态变量中。
关于Java:RMI 目标对象的垃圾回收?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12746652/