34

I am getting some sporadic exceptions when making polling RMI calls from one VM to another. The classpaths look consistent between VMs. I am using 64 bit java - the jres are consistent (jdk/v1.6.0_23-64bit). There is an inconsistency in the -XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC between the VMs, but I am not aware if either could be a root cause?

Calling (client) VM has -XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC set, server VM on which the getStatistics() call is made does not.

Couple points to note:-

  1. After encountering the exception, subsequent calls between the same VMs are ok over a period of days - i.e. the Invalid ClassException is a transient issue.

  2. [class] and [fieldname] vary each time the exception is encountered where exception is java.io.InvalidClassException: [class]; incompatible types for field [fieldname]

Is there any problem with making RMI calls (serialization) from a 64 bit VM with -XX:+UseCompressedOops to a another 64bit VM that is not set up to use compressed oops?

The stack:

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

thanks for your help

Nomesh DeSilva
  • 1,649
  • 4
  • 25
  • 43
a_g
  • 341
  • 3
  • 4
  • Are you running any instrumentation tools such as visualvm? Speculation: If they instrument the class when running two classes can be different for a while. – Jayan Dec 26 '14 at 04:23

5 Answers5

1

Just to be sure, the Class in both VMs are sharing same compiled version of the classes? Could you try re-compiling and adding same jar to both VMs.

I hope that is already taken care.

Mohammed
  • 324
  • 3
  • 4
1

Most likely it is a simple case of 2 different compiled versions of the same class. But sometimes that can be tough to track down. Check the following:

  • Make sure you have the same jar being used in both JVMs (do binary diff on them)
  • Make sure you don't have multiple versions of the same jar in the classpath
  • If you are using an app server and have multiple apps deployed, each one uses its own classloader as well as the global one, so sometimes this can be in conflict.
Jeffrey Do
  • 11
  • 1
0

Hmmh. Would it be possible reproduce the situation with a debugger attached? Having a breakpoint at throw in ObjectStreamClass where exception is thrown:

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

When exception is thrown, you could at least inspect getTypeCode return values. Not a solution, I know, but might give some clues/more details to be included in possible bug report.

user207421
  • 305,947
  • 44
  • 307
  • 483
merryprankster
  • 3,369
  • 2
  • 24
  • 26
  • hi, classpaths are consistent. committed is a primitive type (int) – a_g Jul 27 '11 at 10:39
  • exception has also appeared for standard classes e.g. ArrayList... InvalidClassException: java.util.ArrayList; incompatible types for field size – a_g Jul 27 '11 at 10:46
  • Seeing that both of those are `int`, it could of course be a problem between the 32 / 64 bits. If you don't find a definite answer here, you can probably take this to the openjdk / oracle mailing lists... – TC1 Jul 27 '11 at 10:50
  • re: last paragraph implying stale processes - I thought that too initially. But machines have been bounced, and I still get the issue. If it was a regular classpath issue, I would expect the exception to be consistent, but it appears once, and then communication between the same VMs is ok (without restarting them) – a_g Jul 27 '11 at 10:56
-1

Is this option (-XX:+UseCompressedOops) enabled by default for the VM you are using? If no, I would recommend disabling it and trying it out.

Could be a bug in the JRE update that you are using, you can take it up in Oracle forums.

Dmitriy Popov
  • 2,150
  • 3
  • 25
  • 34
abhati
  • 309
  • 1
  • 6
-1

Note first that the -XX:+UseCompressedOops is set on by default since release of 6u23 even if you don't explicitly disable it.

Also, this option just affect the internal representation of pointers to RAM memory, that will not be encoded in the serialized object, so it must not influence the RMI call.

I will bet the problem is related to some bytecode created dynamically in memory that for some reason is not yet available when de-serialized for the first time. This could be the case with libraries like Hibernate and others that wraps the original class with new custom bytecode.

earizon
  • 2,099
  • 19
  • 29