Java: garbage collection for RMI target object?

2019-06-01 09:47发布

问题:

While getting my hands dirty with RMI, I got a java.rmi.NoSuchObjectException exception, which led me to this question: java.rmi.NoSuchObjectException: no such object in table but my question is different.

I'm creating the impl object in my main method and hence in the main thread. If I do this:

FooImpl fi = new FooImpl();
foo = (Foo) UnicastRemoteObject.exportObject(fi, 0);

things work fine.

If I do this:

foo = (Foo) UnicastRemoteObject.exportObject(new FooImpl(), 0);

I see that FooImpl instance is collected and then I get the aforementioned exception.

foo is a static reference that I'm initializng in main; and another remote object returns foo from one of its methods. So a client gets that remote object first, then gets foo from it, and then calls a method on foo and that's when I get the exception as explained above. So why is it happening this way?

EDIT: here's my main method

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!");        
}

In client, I'm getting hello and calling a method on it which gives me foo and then calling a method on foo.

EDIT2: If I use

Hello stub = (Hello) UnicastRemoteObject.exportObject(new Server(), 0);

and bind foo first and then hello, then same exception is thrown when I try to access hello because now it's Server instance which is getting collected. Really weird stuff!

回答1:

Both approaches are liable to fail. There's no real difference between them in terms of variable scoping.

The problem more usually seen in these situations is the Registry itself, when created by LocateRegistry.createRegistry(), which you aren't doing. If you were, the created Registry itself can be GC'd too: you must keep the Registry reference in a static variable. Then it won't be GC'd, and it will prevent the stub foo from being GC'd, and the stub will keep the FooImpl from being DGC'd and therefore GC'd.

In your case you would be better off keeping the remote object references (servers, not stubs) in static variables.