Java DGC测试中出现意外结果-未引用()方法
我正在做一些关于JavaRMI分布式GC的测试 这是我的测试项目: 服务器端 Bootstrap.javaJava DGC测试中出现意外结果-未引用()方法,java,rmi,Java,Rmi,我正在做一些关于JavaRMI分布式GC的测试 这是我的测试项目: 服务器端 Bootstrap.java public interface Bootstrap extends Remote { public Runnable getClient() throws RemoteException; } public class ClientBootstrap { public static void main(String[] args) { if
public interface Bootstrap extends Remote
{
public Runnable getClient() throws RemoteException;
}
public class ClientBootstrap
{
public static void main(String[] args)
{
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Runnable client = null;
try
{
Bootstrap bootstrapServer = (Bootstrap)
Naming.lookup("//" + args[0] + ":1099/BootstrapServer");
client = bootstrapServer.getClient();
}
catch (MalformedURLException | RemoteException | NotBoundException e)
{
e.printStackTrace();
}
client.run();
}
}
Login.java
public interface Login extends Remote
{
public String login() throws RemoteException;
}
BootstrapServer.java
public class BootstrapServer implements Bootstrap, Unreferenced
{
private final Login loginServerStub;
public BootstrapServer(Login loginServerStub, int port)
throws RemoteException
{
this.loginServerStub = loginServerStub;
UnicastRemoteObject.exportObject(this, port);
}
@Override
public Runnable getClient() throws RemoteException
{
return new Client(loginServerStub);
}
@Override
public void unreferenced()
{
System.out.println("unreferenced() method called on BootstrapServer");
}
}
public class LoginServer implements Login, Unreferenced
{
public LoginServer(int port) throws RemoteException
{
UnicastRemoteObject.exportObject(this, port);
}
@Override
public String login() throws RemoteException
{
return "Login successful";
}
@Override
public void unreferenced()
{
System.out.println("unreferenced() method called on LoginServer");
}
}
LoginServer.java
public class BootstrapServer implements Bootstrap, Unreferenced
{
private final Login loginServerStub;
public BootstrapServer(Login loginServerStub, int port)
throws RemoteException
{
this.loginServerStub = loginServerStub;
UnicastRemoteObject.exportObject(this, port);
}
@Override
public Runnable getClient() throws RemoteException
{
return new Client(loginServerStub);
}
@Override
public void unreferenced()
{
System.out.println("unreferenced() method called on BootstrapServer");
}
}
public class LoginServer implements Login, Unreferenced
{
public LoginServer(int port) throws RemoteException
{
UnicastRemoteObject.exportObject(this, port);
}
@Override
public String login() throws RemoteException
{
return "Login successful";
}
@Override
public void unreferenced()
{
System.out.println("unreferenced() method called on LoginServer");
}
}
Client.java
public class Client implements Runnable, Serializable
{
private static final long serialVersionUID = 2743368372506517302L;
private final Login loginServerStub;
public Client(Login loginServerStub)
{
this.loginServerStub = loginServerStub;
}
@Override
public void run()
{
System.out.println("Hi! I'm the client.");
System.out.println("This is the remote reference of the login server:");
System.out.println(loginServerStub + "\n");
System.out.println("I'm trying to invoke the login method:");
try
{
System.out.println(loginServerStub.login());
}
catch (RemoteException e)
{
e.printStackTrace();
}
}
}
Setup.java
public class Setup
{
public static void main(String args[])
{
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Bootstrap bootstrapServer = null;
try
{
Login loginServer = new LoginServer(Integer.parseInt(args[0]));
bootstrapServer = new BootstrapServer(loginServer,
Integer.parseInt(args[1]));
LocateRegistry.createRegistry(1099);
Registry rmiRegistry = LocateRegistry.getRegistry();
rmiRegistry.bind("BootstrapServer", bootstrapServer);
}
catch (RemoteException | AlreadyBoundException e)
{
e.printStackTrace();
}
}
}
重要的是BootstrapServer维护LoginServer的远程引用。
当客户机调用getClient方法时,BootstrapServer将创建一个新的客户机对象。
在客户端对象中封装了LoginServer的远程引用。
最后,对客户端对象进行序列化,并将其发送到客户端应用程序
客户端
ClientBootstrap.java
public interface Bootstrap extends Remote
{
public Runnable getClient() throws RemoteException;
}
public class ClientBootstrap
{
public static void main(String[] args)
{
if (System.getSecurityManager() == null)
System.setSecurityManager(new SecurityManager());
Runnable client = null;
try
{
Bootstrap bootstrapServer = (Bootstrap)
Naming.lookup("//" + args[0] + ":1099/BootstrapServer");
client = bootstrapServer.getClient();
}
catch (MalformedURLException | RemoteException | NotBoundException e)
{
e.printStackTrace();
}
client.run();
}
}
客户端应用程序只运行服务器发送的客户端对象
这是客户端应用程序的输出:
user@ubuntu:~/javarmi/UnreferencedTestClient$ ./client_launcher.sh
Hi! I'm the client.
This is the remote reference of the login server:
LoginServer_Stub[UnicastRef [liveRef: [endpoint:[127.0.1.1:42000](remote),objID:[711ad51f:148ebcdecc7:-7fff, 6312833096912673336]]]]
I'm trying to invoke the login method:
Login successful
user@ubuntu:~/javarmi/UnreferencedTestClient$
一分钟后,我更改了服务器端应用程序打印的leaseValue和checkInterval参数:
unreferenced() method called on LoginServer
请注意,由于rmiregistry维护远程引用,因此从未调用BootstrapServer上的未引用方法
问题是:如果BootstrapServer获得了loginServerStub引用,为什么会在LoginServer上调用unreferenced方法
谢谢。在服务器JVM中,BootstrapServer没有loginStub引用。它具有对实际服务器的引用。远程对象,而不是其存根。您将变量命名错误。因此,由于BootStrapServer和LoginServer之间没有远程连接,因此前者不是DGC客户机,因此后者可以获得DGC'd
客户端JVM已退出,因此任何地方都没有DGC客户端,因此,也没有什么可以阻止DGC。BootstrapServer没有远程引用,因为该引用没有作为远程方法的参数传递吗?编辑:我尝试在BootstrapServer中添加一个远程方法,以将登录服务器的引用作为此新方法的参数传递,而不是使用构造函数。但结果是一样的,引用不是存根。我不明白为什么会将本地引用而不是存根传递给远程对象,这是文档中所说的:当在远程方法调用中将导出的远程对象作为参数或返回值传递时,而是传递该远程对象的存根。您似乎在询问客户端中发生了什么:请参阅我的第二段。您可以正确地说,远程对象在序列化时被序列化为其自己的存根,但由于客户端JVM立即退出,仍然没有幸存的DGC客户端,因此DGC可能会发生,我知道:我不清楚的是,为什么引导服务器有一个本地引用而不是远程引用。因为您存储了新登录服务器的结果。。。它是一个远程对象,而不是存根。您错误地将构造函数参数和局部变量命名为loginServerStub,但仅此一点并不能使其成为存根。我不明白你为什么不理解自己的代码。