java InvalidClassException:;< class>字段的不兼容类型< fieldname>

mf98qq94  于 2023-05-05  发布在  Java
关注(0)|答案(5)|浏览(149)

当从一个VM到另一个VM进行轮询RMI调用时,我遇到了一些零星的异常。VM之间的类路径看起来是一致的。我使用的是64位java -jres是一致的**(jdk/v1.6.0_23- 64 bit)。虚拟机之间的-XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC存在不一致性,但我不知道这是否是根本原因?
调用(客户端)VM设置了-XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC,调用
getStatistics()的服务器VM没有设置。
需要注意的几点:
1.在遇到异常之后,相同VM之间的后续调用在一段时间内是正常的-即Invalid ClassException是暂时性问题。
1.[class]和[fieldname]在每次遇到异常时都会发生变化,其中异常为java.io.InvalidClassException:[class];字段[fieldname]的不兼容类型
-XX:+UseCompressedOops
64位**虚拟机到另一个未设置为使用压缩oops的64位虚拟机进行RMI调用(序列化)是否有问题?
堆栈:

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

谢谢你的帮助

hof1towb

hof1towb1#

这个选项(-XX:+UseCompressedOops)是否默认为您使用的VM启用,如果没有,我建议禁用它并尝试它。
可能是您正在使用的JRE更新中的一个错误,您可以在Oracle论坛中讨论它。

rks48beu

rks48beu2#

首先请注意,自6 u23发布以来,-XX:+UseCompressedOops默认设置为打开,即使您没有显式禁用它。
此外,这个选项只影响指向RAM内存的指针的内部表示,而不会在序列化对象中进行编码,因此它一定不会影响RMI调用。
我敢打赌,这个问题与内存中动态创建的一些字节码有关,由于某种原因,当第一次反序列化时,这些字节码还不可用。这可能是像Hibernate和其他使用新的自定义字节码 Package 原始类的库的情况。

46scxncf

46scxncf3#

只是为了确定,两个VM中的类共享相同的类编译版本?你可以尝试重新编译并添加相同的jar到两个虚拟机。
我希望这已经得到了照顾。

uyto3xhc

uyto3xhc4#

嗯,有没有可能在连接调试器的情况下重现这种情况?在ObjectStreamClass中的throw处有一个断点,在此抛出异常:

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

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

mgdq6dx1

mgdq6dx15#

最有可能的情况是同一个类有两个不同的编译版本。但有时候很坚韧追查。检查以下内容:

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

相关问题