InvalidClassException: <class>; 不兼容的类型,字段名称为 <fieldname>。

34

在从一个VM向另一个VM进行轮询RMI调用时,我遇到了一些零星的异常。两个VM之间的类路径看起来是一致的。我正在使用64位Java- jres是一致的(jdk/v1.6.0_23-64bit)

两个VM中的-XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC存在不一致性,但我不知道这些是否可能是根本原因?

调用(客户端)VM设置了-XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC,在其中进行getStatistics()调用的服务器VM没有进行此类设置。

需要注意以下几点:

  1. 在遇到异常后,随后在同一VM之间进行的调用在数天内都是正常的——即无效的ClassException是暂时的问题。

  2. [class]和[fieldname]每次遇到异常时都会有所不同,其中异常是java.io.InvalidClassException: [class]; incompatible types for field [fieldname]

使用带有-XX:+UseCompressedOops64位 VM进行RMI调用(序列化)到一个未设置压缩oops的另一个64位VM中是否存在问题?

堆栈信息:

java.rmi.UnmarshalException: error unmarshalling return; nested exception is:
    java.io.InvalidClassException: testserver.cluster.Status; incompatible types for field committed
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:173)
    at java.rmi.server.RemoteObjectInvocationHandler.invokeRemoteMethod(RemoteObjectInvocationHandler.java:178)
    at java.rmi.server.RemoteObjectInvocationHandler.invoke(RemoteObjectInvocationHandler.java:132)
    at $Proxy14.getStatistics(Unknown Source)
    at testserver.rm.RM$Check.run(RM.java:1593)
Caused by: java.io.InvalidClassException: testserver.cluster.Status; incompatible types for field committed
    at java.io.ObjectStreamClass.matchFields(ObjectStreamClass.java:2210)
    at java.io.ObjectStreamClass.getReflector(ObjectStreamClass.java:2105)
    at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:602)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1582)
    at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1495)
    at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1731)
    at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1328)
    at java.io.ObjectInputStream.readObject(ObjectInputStream.java:350)
    at sun.rmi.server.UnicastRef.unmarshalValue(UnicastRef.java:306)
    at sun.rmi.server.UnicastRef.invoke(UnicastRef.java:155)
    ... 4 more

感谢你的帮助


你是否正在运行任何仪表工具,如visualvm?猜测:如果在运行两个类时对类进行了仪表化处理,则可能存在一段时间内两个类不同。 - Jayan
5个回答

1

为了确保,两个虚拟机中的类是否共享相同编译版本的类? 您可以尝试重新编译并将相同的jar添加到两个虚拟机中。

我希望这已经得到了妥善处理。


我还不能对问题进行评论。 - Mohammed

1

很可能是同一类的两个不同编译版本的简单情况。但有时候这很难追踪。请检查以下内容:

  • 确保在两个JVM中使用相同的jar文件(对它们进行二进制差异比较)
  • 确保类路径中没有多个相同jar文件的版本
  • 如果您正在使用应用服务器并且部署了多个应用程序,则每个应用程序都使用自己的类加载器以及全局类加载器,因此有时会发生冲突。

0

嗯。能否在调试器附加的情况下重现该情况?在ObjectStreamClass中,将断点设置在抛出异常的throw处:

if ((f.isPrimitive() || lf.isPrimitive())
        && f.getTypeCode() != lf.getTypeCode()) {
    throw new InvalidClassException(localDesc.name,
        "incompatible types for field "
                    + f.getName());
}

当抛出异常时,您至少可以检查getTypeCode返回值。我知道这不是解决方案,但可能会提供一些线索/更多细节,以包含在可能的错误报告中。


嗨,类路径是一致的。committed 是一个原始类型(int)。 - a_g
异常也出现在标准类中,例如 ArrayList... InvalidClassException: java.util.ArrayList; size 字段类型不兼容。 - a_g
既然这两个都是“int”,那么问题可能出在32/64位之间。如果你在这里找不到明确的答案,你可以把它带到openjdk/oracle邮件列表中... - TC1
关于最后一段暗示的过期进程 - 我也最初认为是这样。但已经重新启动了机器,问题还存在。如果这是一个常规的类路径问题,我会期望异常是一致的,但它仅出现一次,然后同一虚拟机之间的通信是正常的(无需重新启动它们)。 - a_g

-1
这个选项(-XX:+UseCompressedOops)在您使用的虚拟机中是否默认启用?如果没有,默认建议禁用并尝试一下。
可能是您使用的JRE更新中的一个错误,您可以在Oracle论坛上提出。

UseCompressedOops与序列化完全无关。 - user207421
UseCompressedOops与序列化完全无关。 - undefined

-1
请注意,自6u23版本发布以来,默认情况下已启用-XX:+ UseCompressedOops选项,即使您没有明确禁用它。
此外,此选项仅影响指向RAM内存的指针的内部表示形式,不会编码在序列化对象中,因此不应影响RMI调用。
我敢打赌问题与动态创建的字节码有关,这些字节码在第一次反序列化时由于某种原因尚不可用。这可能是像Hibernate等库的情况,它们使用新的自定义字节码包装原始类。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接