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)
[...]
Так что это происходит не только во время инициализации класса, но и в нескольких собранных мною примерах что-то в реализации отражений кажется виновником.
Ява в версии 8
java version "1.8.0_144"
nodetool
Панель запуска всегда использует один и тот же путь к классам. И там нет странных классов (или дополнительных загрузчиков классов). Одна и та же установка выполняется на сотнях одинаковых узлов (в Linux).
Мои лучшие результаты поиска для NoClassDefFoundError wrong name
ссылаются на исполнения, где для запуска использовалось упрощенное имя класса java
, а не полное имя. Это не проблема здесь. Также имена в сообщениях об ошибках идентичны.
Так что может вызвать такое "неправильное имя" NoClassDefFoundError
ошибки для классов "начальной загрузки"?
3 ответа
Согласно трассировке стека, идентификатор исключения генерируется в вызовах getDeclaredFields0
, Однако это не то место, откуда изначально пришло исключение. Согласно исходному коду OpenJDK, в базе кода нет ничего, что выдает исключение с "неправильным именем" в сообщении об исключении. Сообщение пришло откуда-то еще.
Я сильно подозреваю, что это фактически повторное сообщение о проблеме, которая произошла в первый раз, когда какой-то класс был загружен или инициализирован. Что происходит, так это то, что загрузчик классов обнаруживает проблему в первый раз, помечает нарушающий внутренний объект класса как "плохой", а затем выдает ошибку. Согласно javadoc, приложения не должны пытаться восстанавливаться после этого. Но если вы это сделаете, а затем попытаетесь каким-то образом использовать "плохой" класс, первоначальная проблема будет снова сообщена как NoClassDefFoundError
с первоначальной причиной.
Так что же означает причина?
Трудно сказать, потому что у нас нет стековой трассировки для исходного исключения; то есть тот, где загрузка / инициализация класса сначала не удалась. Если вы можете найти эту трассировку стека, мы можем отследить стороннюю библиотеку, которая это сделала. Это почти наверняка происходит в загрузчике классов.
Очевидное значение состоит в том, что файл класса содержит имя класса, которое не совпадает с именем в байт-кодах классов. Тем не менее, нам нужно проверить код загрузчика классов, чтобы быть уверенным.
Так почему же это происходит периодически?
Возможно, потому что в прикладной JVM есть много загрузчиков классов, и только их подмножество "загрязнило" пространство имен своего класса этим плохим классом.
Это может быть плохой новостью. Предполагается, что в ядре приложения может возникнуть проблема синхронизации.
Во всяком случае, нет достаточных доказательств, чтобы сделать обоснованные выводы.
Нижняя линия
Основываясь на доказательствах, я бы предположил, что это результат некоего "переплетения кода" или "инженерии байт-кода", которая пошла не так. В качестве дальнейшего предположения я бы сказал, что некоторый дочерний загрузчик классов не делегирует должным образом и по ошибке попытался обработать встроенный класс. (Может даже оказаться, что рассматриваемый загрузчик классов знает, что он никогда не должен обрабатывать класс "java.lang.*", И у него есть неясный способ сказать это.)
Зачем? возможно, потому что кто-то / что-то явно добавил "rt.jar" к некоторому пути к классам, на котором он не должен быть.
Для дальнейшей диагностики первое, что нам нужно, это оригинальная трассировка стека, которая сообщает нам, какой загрузчик классов нанес первоначальный ущерб.
Я думаю, что это нехватка ресурсов, которые вызывают проблемы, как тайм-аут разъема или что-то. Вы видите журнал из вашего примера?; nodeprobe подключается через jmx или пытается подключиться, тогда возникает ошибка? Это очень типичная ошибка, которая также может вызвать другую временную ошибку на дерьме (обычно дерьмо OS/netowrk OS), таким образом: включает в себя вашу строку и даже объектную ошибку, и в заключение это имеет смысл. возможно, вам следует проверить свой ресурс, когда произойдет ошибка. я знаю, что это своего рода уловка 22 в том, что монитор ресурсов вызывает нехватку ресурсов; но это случилось хе-хе
Поскольку не найдено ни одной базовой библиотеки 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 и установить переменные окружения.