Подтвердить что ты не робот

InvalidClassException: <класs>; несовместимые типы для поля <имя_файлa>

Я получаю некоторые спорадические исключения при опросе звонков RMI с одной виртуальной машины на другую. Пути классов выглядят согласованно между виртуальными машинами. Я использую 64-битную java - jres соответствуют (jdk/v1.6.0_23-64bit). Существует несогласованность в -XX:+UseCompressedOops flag & -XX:+UseConcMarkSweepGC между виртуальными машинами, но я не знаю, могла ли это быть основной причиной?

У вызывающей (клиентской) виртуальной машины установлена ​​ -XX:+UseCompressedOops & -XX:+UseConcMarkSweepGC, серверная VM, на которой выполнен вызов getStatistics(), не работает.

Пара отмечает: -

  • После обнаружения исключения последующие вызовы между тем же ВМ в порядке в течение нескольких дней - т.е. Invalid ClassException является временной проблемой.

  • [class] и [fieldname] изменяются каждый раз, когда исключение встречается там, где исключение java.io.InvalidClassException: [класс]; несовместимые типы для поле [fieldname]

Есть ли проблема с вызовом RMI (сериализация) с 64-разрядной виртуальной машины с -XX:+UseCompressedOops на другую 64-битную виртуальную машину, которая не настроена на использование сжатых oops?

Стек:

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

спасибо за помощь

4b9b3361

Ответ 1

Hmmh. Можно ли воспроизвести ситуацию с прикрепленным отладчиком? Наличие точки останова в throw в ObjectStreamClass, где выбрано исключение:

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

Когда выбрано исключение, вы можете хотя бы проверить возвращаемые значения getTypeCode. Не решение, я знаю, но может дать некоторые подсказки/более подробную информацию, которая будет включена в возможный отчет об ошибке.

Ответ 2

Эта опция (-XX: + UseCompressedOops) включена по умолчанию для виртуальной машины, которую вы используете, если нет, я бы рекомендовал отключить ее и попробовать.

Может быть ошибка в обновлении JRE, которое вы используете, вы можете принять его на форумах Oracle.

Ответ 3

Прежде всего отметим, что -XX: + UseCompressedOops устанавливается по умолчанию с момента выпуска 6u23, даже если вы явно не отключили его.

Кроме того, этот параметр влияет только на внутреннее представление указателей на RAM-память, которые не будут закодированы в сериализованном объекте, поэтому он не должен влиять на вызов RMI.

Готов поспорить, что проблема связана с каким-то байт-кодом, созданным динамически в памяти, который по какой-то причине еще не доступен, когда де-сериализован в первый раз. Это может иметь место в таких библиотеках, как Hibernate и другие, которые обертывают исходный класс новым пользовательским байтовым кодом.

Ответ 4

Чтобы быть уверенным, что класс в обеих виртуальных машинах использует одну и ту же скомпилированную версию классов? Не могли бы вы попытаться перекомпилировать и добавить одну банку для обеих виртуальных машин.

Я надеюсь, что это уже позаботится.