Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/358.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
java.rmi.NoSuchObjectException:表中没有此类对象_Java_Exception_Rmi - Fatal编程技术网

java.rmi.NoSuchObjectException:表中没有此类对象

java.rmi.NoSuchObjectException:表中没有此类对象,java,exception,rmi,Java,Exception,Rmi,我正在编写一个非常简单的RMI服务器,我在单元测试中看到了间歇性的java.RMI.NoSuchObjectExceptions 我在同一个对象上有一个远程方法调用字符串,虽然前几个调用已经完成,但后几个调用有时会失败。我没有做任何事情来注销中间的服务器对象 这些错误并不总是出现,如果我设置断点,它们往往不会出现。这些是海森堡吗?当通过减慢的调试器执行来查看它们时,它们的竞争条件会消失吗?我的测试或服务器代码中没有多线程(尽管可能在RMI堆栈中?) 我通过Eclipse的JUnit插件在MacO

我正在编写一个非常简单的RMI服务器,我在单元测试中看到了间歇性的
java.RMI.NoSuchObjectExceptions

我在同一个对象上有一个远程方法调用字符串,虽然前几个调用已经完成,但后几个调用有时会失败。我没有做任何事情来注销中间的服务器对象

这些错误并不总是出现,如果我设置断点,它们往往不会出现。这些是海森堡吗?当通过减慢的调试器执行来查看它们时,它们的竞争条件会消失吗?我的测试或服务器代码中没有多线程(尽管可能在RMI堆栈中?)

我通过Eclipse的JUnit插件在MacOSX10.5(Java1.5)上运行它,RMI服务器和客户端都在同一个JVM中


是什么导致了这些异常?

不看代码(我想代码太大了,无法在这里发布)就很难回答这个问题。然而,使用奥卡姆剃须刀,你有两种可能

  • 服务器对象必须以某种方式注销
  • 因为断点可以阻止错误,所以这肯定是一种竞争条件

我建议您仔细检查代码路径,记住上面提到的两点。

< P>其他一些要考虑的问题:首先是引用对象实例,还是存根接口本身消失了?如果某个对象实例消失了,这是因为通常的原因,它被取消引用并被GC'd,但是如果它是接口,那么您的RMI服务器端点循环会因为某种原因退出

到目前为止,我发现最好的调试工具是打开java.rmi.server.logCalls=true属性(请参阅) 并观看所有精彩的信息流下您的日志窗口。这告诉我每次都发生了什么


JO保持对实现
java.rmi.Remote
接口的对象的强引用,使其保持,即不符合垃圾收集的条件。

下面是一个简短的程序,演示了一个。该脚本是自包含的,在单个JVM中创建RMI注册表以及“客户机”和“服务器”

只需复制此代码并将其保存在名为
RMITest.java
的文件中。使用您选择的命令行参数编译和调用:

  • -gc
    (默认)显式指示JVM在服务器启动后但在客户端连接到服务器之前“尽最大努力”运行垃圾收集器。如果对
    Remote
    对象的强引用被释放,这可能会导致垃圾收集器回收
    Remote
    对象。回收
    远程
    对象后,当客户端连接时,会观察到
    java.rmi.NoSuchObjectException
  • -nogc
    不显式请求垃圾回收。这可能会导致客户端保持对
    远程
    对象的访问,无论强引用是保持还是释放,除非服务器启动和客户端调用之间有足够的延迟,从而使系统“自然”运行调用垃圾收集器并回收
    远程
    对象
  • -按住
    保留对
    远程
    对象的强引用。在这种情况下,类变量引用
    Remote
    对象
  • -release
    (默认)将释放对
    远程
    对象的强引用。在这种情况下,方法变量引用
    Remote
    对象。方法返回后,强引用将丢失
  • -delay
    服务器启动和客户端调用之间等待的秒数。插入延迟为垃圾收集器“自然”运行提供了时间。这模拟了一个最初“工作”的进程,但在经过一段重要时间后失败。注意秒数前没有空格。示例:
    -delay5
    将在服务器启动5秒后进行客户端调用
程序行为可能会因机器和JVM的不同而不同,因为像
System.gc()
这样的东西只是提示,设置
-delay
选项是对垃圾收集器行为的猜测

在我的机器上,在编译
javac RMITest.java
之后,我看到以下行为:

$ java RMITest -nogc -hold
received: foo
$ java RMITest -nogc -release
received: foo
$ java RMITest -gc -hold
received: foo
$ java RMITest -gc -release
Exception in thread "main" java.rmi.NoSuchObjectException: no such object in table
    at sun.rmi.transport.StreamRemoteCall.exceptionReceivedFromServer(StreamRemoteCall.java:255)
    at sun.rmi.transport.StreamRemoteCall.executeCall(StreamRemoteCall.java:233)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:142)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
    at $Proxy0.remoteOperation(Unknown Source)
    at RMITest.client(RMITest.java:69)
    at RMITest.main(RMITest.java:46)
以下是源代码:

import java.rmi.Remote;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.UnicastRemoteObject;
import static java.util.concurrent.TimeUnit.*;

interface RemoteOperations extends Remote {
    String remoteOperation() throws RemoteException;
}

public final class RMITest implements RemoteOperations {
    private static final String REMOTE_NAME = RemoteOperations.class.getName();
    private static final RemoteOperations classVariable = new RMITest();

    private static boolean holdStrongReference = false;
    private static boolean invokeGarbageCollector = true;
    private static int delay = 0;

    public static void main(final String... args) throws Exception {
        for (final String arg : args) {
            if ("-gc".equals(arg)) {
                invokeGarbageCollector = true;
            } else if ("-nogc".equals(arg)) {
                invokeGarbageCollector = false;
            } else if ("-hold".equals(arg)) {
                holdStrongReference = true;
            } else if ("-release".equals(arg)) {
                holdStrongReference = false;
            } else if (arg.startsWith("-delay")) {
                delay = Integer.parseInt(arg.substring("-delay".length()));
            } else {
                System.err.println("usage: javac RMITest.java && java RMITest [-gc] [-nogc] [-hold] [-release] [-delay<seconds>]");
                System.exit(1);
            }
        }
        server();
        if (invokeGarbageCollector) {
            System.gc();
        }
        if (delay > 0) {
            System.out.println("delaying " + delay + " seconds");
            final long milliseconds = MILLISECONDS.convert(delay, SECONDS);
            Thread.sleep(milliseconds);
        }
        client();
        System.exit(0); // stop RMI server thread
    }

    @Override
    public String remoteOperation() {
        return "foo";
    }

    private static void server() throws Exception {
        // This reference is eligible for GC after this method returns
        final RemoteOperations methodVariable = new RMITest();
        final RemoteOperations toBeStubbed = holdStrongReference ? classVariable : methodVariable;
        final Remote remote = UnicastRemoteObject.exportObject(toBeStubbed, 0);
        final Registry registry = LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
        registry.bind(REMOTE_NAME, remote);
    }

    private static void client() throws Exception {
        final Registry registry = LocateRegistry.getRegistry();
        final Remote remote = registry.lookup(REMOTE_NAME);
        final RemoteOperations stub = RemoteOperations.class.cast(remote);
        final String message = stub.remoteOperation();
        System.out.println("received: " + message);
    }
}
导入java.rmi.Remote;
导入java.rmi.RemoteException;
导入java.rmi.registry.LocateRegistry;
导入java.rmi.registry.registry;
导入java.rmi.server.UnicastRemoteObject;
导入静态java.util.concurrent.TimeUnit.*;
接口RemoteOperations扩展了远程{
字符串remoteOperation()引发RemoteException;
}
公共最终类RMITest实现远程操作{
私有静态最终字符串REMOTE_NAME=RemoteOperations.class.getName();
private static final RemoteOperations classVariable=new RMITest();
私有静态布尔holdStrongReference=false;
私有静态布尔invokeGarbageCollector=true;
专用静态整数延迟=0;
公共静态void main(最终字符串…args)引发异常{
for(最终字符串arg:args){
如果(“-gc.”等于(arg)){
invokeGarbageCollector=true;
}如果(“-nogc.”等于(arg)){
invokeGarbageCollector=false;
}否则,如果(“-hold.”等于(arg)){
holdStrongReference=true;
}否则,如果(“-release.”等于(arg)){
holdStrongReference=false;
}else if(参数startsWith(“-delay”)){
delay=Integer.parseInt(arg.substring(“-delay.length());
}否则{
System.err.println(“用法:javac RMITest.java&&java RMITest[-gc]
public interface MyRemoteInterface extedns Remote {
    ...
}

public class MyRemoteObject implements MyRemoteInterface {
    ...
}

public static MyRemoteObject obj = new MyRemoteObject();

public static void main(String[] args) {
    //removing cast to MyRemoteInterface fixes the problem
    this.obj = UnicastRemoteObject.exportObject((MyRemoteInterface) this.obj, 0);

    //unless the above cast is removed, this throws NoSuchObjectException occasionally
    LocateRegisry.getRegistry("127.0.0.1", 1099).bind("name", this.obj);
}
...
private static ServiceImpl serviceImpl = null;

public static void register (int port) {
    serviceImpl = new ServiceImpl();
    Registry registry = LocateRegistry.createRegistry(port);
    registry.rebind ("serviceImpl", serviceImpl);
}

public static void main(String[] args) throws RemoteException, NotBoundException {
    register(1099);    
    ...the rest of your code...
}