无效类异常:<类>;字段<字段名称>不兼容的类型

2022-09-01 14:49:24

在从一个 VM 到另一个 VM 进行轮询 RMI 调用时,我遇到了一些零星的异常。VM 之间的类路径看起来是一致的。我使用的是64位java - jres是一致的(jdk / v1.6.0_23-64bit)。VM 之间存在不一致,但我不知道这两者是否可能是根本原因?-XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC

调用(客户端)VM 已设置,对其进行 getStatistics() 调用的服务器 VM 未设置。-XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC

注意事项:-

  1. 遇到异常后,同一 VM 之间的后续调用在几天内正常 - 即无效类异常是暂时性问题。

  2. [class] 和 [fieldname] 每次遇到异常时都会有所不同,其中异常是 java.io.InvalidClassException: [class];字段 [字段名] 的类型不兼容

64 位 VM 到另一个未设置为使用压缩 oop 的 64 位 VM 进行 RMI 调用(序列化)是否存在任何问题?-XX:+UseCompressedOops

堆栈:

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

感谢您的帮助


答案 1

默认情况下是否为您正在使用的VM启用了此选项(-XX:+UseCompressedOops),如果没有,我建议禁用它并尝试一下。

可能是您正在使用的JRE更新中的一个错误,您可以在Oracle论坛中使用它。


答案 2

首先请注意,自 6u23 发布以来,默认情况下会设置 -XX:+UseCompressedOops,即使您没有显式禁用它。

此外,此选项仅影响指向 RAM 内存的指针的内部表示形式,该指针不会在序列化对象中编码,因此它不得影响 RMI 调用。

我敢打赌,这个问题与在内存中动态创建的某些字节码有关,由于某种原因,这些字节码在第一次反序列化时尚不可用。对于像Hibernate这样的库和其他用新的自定义字节码包装原始类的库来说,情况可能就是这种情况。