java.rmi.NoSuchObjectException:表中没有这样的对象 [英] java.rmi.NoSuchObjectException: no such object in table

查看:1922
本文介绍了java.rmi.NoSuchObjectException:表中没有这样的对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am writing a very simple RMI server, and I am seeing intermittent java.rmi.NoSuchObjectExceptions in the unit tests.

我在同一个对象上有一串远程方法调用,而前几个调用时,后面的调用有时会失败。我没有做任何事情来取消注册服务器对象。

I have a string of remote method calls on the same object, and while the first few go through, the later ones will sometimes fail. I am not doing anything to unregister the server object in between.

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

These error do not appear always, and if I put in breakpoints they tend to not appear. Are those Heisenbugs, whose race conditions dissolve when looking at them through the slowed down execution of the debugger? There is no multi-threading going on in my test or server code (though maybe inside of the RMI stack?).

我在Mac OS X 10.5上运行它( Java 1.5)通过Eclipse的JUnit插件,RMI服务器和客户端都在同一个JVM中。

I am running this on Mac OS X 10.5 (Java 1.5) through Eclipse's JUnit plugin, and the RMI server and client are both in the same JVM.

什么可能导致这些异常?

What can cause these exceptions?

推荐答案

保持对实现 java.rmi.Remote 接口的对象的强引用它仍然是可达,即不合格垃圾收集。

Keep a strong reference to the object that implements the java.rmi.Remote interface so that it remains reachable, i.e. ineligible for garbage collection.

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

Below is a short program that demonstrates a java.rmi.NoSuchObjectException. The script is self-contained, creating an RMI registry as well as a "client" and a "server" in a single JVM.

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

Simply copy this code and save it in a file named RMITest.java. Compile and invoke with your choice of command line arguments:


  • -gc (默认)显式指示JVM在服务器启动后但在客户端连接到服务器之前尽最大努力运行垃圾收集器。如果对远程的强引用,这可能会导致垃圾收集器回收远程对象对象已发布 。在回收远程对象后客户端连接时,会观察到 java.rmi.NoSuchObjectException

  • -nogc 不要显式请求垃圾回收。这可能导致客户端仍然可以访问远程对象,无论是否保留或释放强引用,除非有足够的延迟在服务器启动和客户端调用之间,以便系统自然地调用垃圾收集器并回收远程对象

  • -hold 保留对远程对象的强引用。在这种情况下,类变量引用远程对象。

  • -release (默认)将释放对远程对象的强引用。在这种情况下,方法变量引用远程对象。方法返回后,强参考将丢失。

  • -delay< S> 服务器启动和客户端调用之间等待的秒数。插入延迟为垃圾收集器自然地运行提供了时间。这模拟了一个最初有效的过程,但在经过一段时间后失败了。请注意,秒数之前没有空格。示例: -delay5 将在服务器启动后5秒进行客户端调用。

  • -gc (default) Explicitly instruct the JVM to make "a best effort" to run the garbage collector after the server is started, but before the client connects to the server. This will likely cause the Remote object to be reclaimed by the garbage collector if the strong reference to the Remote object is released. A java.rmi.NoSuchObjectException is observed when the client connects after the Remote object is reclaimed.
  • -nogc Do not explicitly request garbage collection. This will likely cause the Remote object to remain accessible by the client regardless of whether a strong reference is held or released unless there is a sufficient delay between the server start and the client call such that the system "naturally" invokes the garbage collector and reclaims the Remote object.
  • -hold Retain a strong reference to the Remote object. In this case, a class variable refers to the Remote object.
  • -release (default) A strong reference to the Remote object will be released. In this case, a method variable refers to the Remote object. After the method returns, the strong reference is lost.
  • -delay<S> The number of seconds to wait between server start and the client call. Inserting a delay provides time for the garbage collector to run "naturally." This simulates a process that "works" initially, but fails after some significant time has passed. Note there is no space before the number of seconds. Example: -delay5 will make the client call 5 seconds after the server is started.

程序行为可能因机器和JVM到JVM而异,因为像 System.gc()之类的东西只是提示并设置 - 延迟< S> 选项是关于垃圾收集器行为的猜谜游戏。

Program behavior will likely vary from machine to machine and JVM to JVM because things like System.gc() are only hints and setting the -delay<S> option is a guessing game with respect to the behavior of the garbage collector.

在我的机器上,<$ c $之后c> javac RMITest.java 要编译,我看到这种行为:

On my machine, after javac RMITest.java to compile, I see this behavior:

$ 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.NoSuchObjectException:表中没有这样的对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆