NoClassDefFoundError "неправильное имя" для класса в пакете java.lang

Я запускаю Cassandra 2.2.11 (и не буду обновлять) на хосте. Периодически, в задании cron, я запускаю команды nodetool для мониторинга. nodetool реализуется как еще один Java-процесс, который использует JMX для общения с процессом Java Cassandra. Я запускаю пять или около того команд каждую минуту.

Время от времени (не в любом распознаваемом шаблоне) выполнение nodetool завершится неудачно с NoClassDefFoundError, который относится к классу из java.lang. Например,

java.lang.NoClassDefFoundError: java/lang/Thread (wrong name: java/lang/Thread)
    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
    at java.lang.Class.getDeclaredField(Class.java:2068)
    at java.util.concurrent.FutureTask.<clinit>(FutureTask.java:476)
    at java.util.concurrent.ScheduledThreadPoolExecutor.scheduleWithFixedDelay(ScheduledThreadPoolExecutor.java:590)
    at sun.rmi.transport.tcp.TCPChannel.free(TCPChannel.java:347)
    at sun.rmi.server.UnicastRef.free(UnicastRef.java:431)
    at sun.rmi.server.UnicastRef.done(UnicastRef.java:448)
    at sun.rmi.registry.RegistryImpl_Stub.lookup(Unknown Source)
    at com.sun.jndi.rmi.registry.RegistryContext.lookup(RegistryContext.java:132)
    at com.sun.jndi.toolkit.url.GenericURLContext.lookup(GenericURLContext.java:205)
    at javax.naming.InitialContext.lookup(InitialContext.java:417)
    at javax.management.remote.rmi.RMIConnector.findRMIServerJNDI(RMIConnector.java:1955)
    at javax.management.remote.rmi.RMIConnector.findRMIServer(RMIConnector.java:1922)
    at javax.management.remote.rmi.RMIConnector.connect(RMIConnector.java:287)
    at javax.management.remote.JMXConnectorFactory.connect(JMXConnectorFactory.java:270)
    at org.apache.cassandra.tools.NodeProbe.connect(NodeProbe.java:183)
    at org.apache.cassandra.tools.NodeProbe.<init>(NodeProbe.java:150)
    at org.apache.cassandra.tools.NodeTool$NodeToolCmd.connect(NodeTool.java:302)
    at org.apache.cassandra.tools.NodeTool$NodeToolCmd.run(NodeTool.java:242)
    at org.apache.cassandra.tools.NodeTool.main(NodeTool.java:158)

В этой трассе стека ошибка возникает во время инициализации класса для FutureTask. Я также видел

java.lang.NoClassDefFoundError: java/lang/Object (wrong name: java/lang/Object)
    at java.lang.Class.getDeclaredMethods0(Native Method)
    at java.lang.Class.privateGetDeclaredMethods(Class.java:2701)
    at java.lang.Class.getDeclaredMethod(Class.java:2128)
    at java.lang.invoke.MethodHandleImpl$Lazy.<clinit>(MethodHandleImpl.java:614)
    [...]

но также

java.lang.NoClassDefFoundError: java/lang/String (wrong name: java/lang/String)
    at java.lang.Class.getDeclaredFields0(Native Method)
    at java.lang.Class.privateGetDeclaredFields(Class.java:2583)
    at java.lang.Class.getDeclaredField(Class.java:2068)
    at java.io.ObjectStreamClass.getDeclaredSUID(ObjectStreamClass.java:1703)
    at java.io.ObjectStreamClass.access$700(ObjectStreamClass.java:72)
    at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:484)
    at java.io.ObjectStreamClass$2.run(ObjectStreamClass.java:472)
    [...]

Таким образом, это происходит не только во время инициализации класса, но и в нескольких образцах, которые я собрал, что-то в реализации отражения кажется виновником.

Java находится в версии 8

java version "1.8.0_144"

Пуск nodetool всегда использует один и тот же путь к классам. И там нет странных классов (или дополнительных загрузчиков классов). Такая же установка выполняется через сотни одинаковых узлов (в Linux).

Мои лучшие результаты поиска для NoClassDefFoundError wrong name относятся к исполнениям, где для запуска java вместо более полного имени использовалось упрощенное имя класса. Это не проблема. Кроме того, имена в сообщениях об ошибках идентичны.

Итак, что может вызвать такие ошибки "неправильного имени" NoClassDefFoundError для классов "bootstrap"?

Ответ 1

Я думаю, что нехватка ресурсов вызывает такие проблемы, как тайм-аут соединения или что-то в этом роде. Вы видите журнал из своего примера?; nodeprobe подключается через jmx или пытается подключиться, тогда возникает ошибка? Это очень типичная ошибка, которая также может вызвать другую ошибку интермита на дерьме (обычно OS/netowrk OS shit), таким образом: включает в себя вашу строку и даже объектную ошибку, в заключение это имеет смысл. может быть, вы должны проверить свой ресурс, когда произойдет ошибка. я знаю, что это своего рода уловка 22, что монитор ресурсов вызывает нехватку ресурсов; но это происходит хехе

Ответ 2

Как ни одна базовая библиотека java не найдена, я думаю, что есть проблемы в вашей установке java или вы не задали переменные среды CLASSPATH и JAVA_HOME. Попробуйте установить CLASSPATH и JAVA_HOME переменные окружения.

export JAVA_HOME="/usr/lib/jvm/java-8-oracle/bin"
export CLASSPATH="/usr/lib/jvm/java-8-oracle/lib"

Если это не сработало, попробуйте переустановить java и установить переменные среды.

Ответ 3

В соответствии с stacktraces, идентификатор исключения вызывается при вызовах getDeclaredFields0. Однако это исключение не изначально. Согласно исходному коду OpenJDK в кодовой базе нет ничего, что генерирует исключение с "неправильным именем" в сообщении об исключении. Сообщение пришло откуда-то еще.

Я сильно подозреваю, что это действительно повторное сообщение о проблеме, которая произошла в первый раз, когда какой-либо класс был загружен или инициализирован. Что происходит, так это то, что загрузчик классов обнаруживает проблему в первый раз, помещает нарушающий внутренний объект класса как "плохой", а затем выдает ошибку. Согласно javadoc, приложения не должны пытаться оправиться от этого. Но если кто-то это делает, а затем пытается каким-то образом использовать "плохой" класс, исходная проблема будет сообщена снова как NoClassDefFoundError с исходной причиной.

Итак, что означает эта причина?

Трудно сказать, потому что у нас нет stacktrace для исходного исключения; то есть тогда, когда сбой первой загрузки/инициализации класса. Если вы обнаружите, что stacktrace, мы можем отслеживать стороннюю библиотеку, которая это сделала. Это почти наверняка происходит в загрузчике классов.

Очевидное значение состоит в том, что файл класса имеет в нем имя класса, которое не соответствует имени в байт-кодах классов. Однако нам нужно будет проверить код загрузчика.

Так почему это происходит с перерывами?

Возможно, потому, что в JVM приложения много загрузчиков классов, и только их подмножество "загрязнило" пространство имен классов с помощью этого плохого класса.

Это может быть плохая новость. Он предполагает, что в ядре приложения может быть какая-то проблема синхронизации.

Во всяком случае, недостаточно доказательств для обоснованных выводов.

Нижняя строка

Основываясь на доказательствах, я бы угадал, что это результат какой-то "перекодировки кода" или "обработки байтового кода", которая пошла не так. В качестве дальнейшего предположения я бы сказал, что некоторый дочерний загрузчик классов не делегирует должным образом и ошибочно пытался обработать встроенный класс. (Возможно, даже тот классный загрузчик знает, что он никогда не должен обрабатывать класс "java.lang. *", И у него есть неясный способ сказать это.)

Почему? возможно, потому что кто-то/что-то явно добавил "rt.jar" к некоторому пути к классам, в котором он не должен быть включен.

Для дальнейшего диагноза первое, что нам нужно, это исходная stacktrace, которая сообщает нам, какой загрузчик классов наносил первоначальный ущерб.