문제

나는 점점 NoClassDefFoundError Java 애플리케이션을 실행할 때.일반적으로 이 문제의 원인은 무엇입니까?

도움이 되었습니까?

해결책

이는 코드가 의존하는 클래스 파일이 있고 컴파일 타임에는 존재하지만 런타임에는 찾을 수 없는 경우 발생합니다.빌드 시간과 런타임 클래스 경로의 차이점을 찾아보세요.

다른 팁

이는 컴파일 타임과 런타임 간의 클래스 경로 불일치로 인한 것일 수도 있지만 반드시 그런 것은 아닙니다.

이 경우 두세 가지 다른 예외를 머릿속에 그대로 유지하는 것이 중요합니다.

  1. java.lang.ClassNotFoundException 이 예외는 클래스 경로에서 클래스를 찾을 수 없음을 나타냅니다.이는 클래스 정의를 로드하려고 했으나 클래스가 클래스 경로에 존재하지 않았음을 나타냅니다.

  2. java.lang.NoClassDefFoundError 이 예외는 JVM이 내부 클래스 정의 데이터 구조에서 클래스 정의를 찾았지만 찾지 못했음을 나타냅니다.이는 클래스 경로에서 로드할 수 없다는 것과는 다릅니다.일반적으로 이는 이전에 클래스 경로에서 클래스를 로드하려고 시도했지만 어떤 이유로 실패했음을 나타냅니다. 이제 클래스를 다시 사용하려고 시도하고 있지만(지난번에 실패했기 때문에 로드해야 함) 이전에 로드하는 데 실패했기 때문에(그리고 다시 실패할 것이라고 합리적으로 의심하기 때문에) 로드하려고 시도하지도 않을 것입니다.이전 오류는 ClassNotFoundException 또는 ExceptionInInitializerError(정적 초기화 블록의 오류를 나타냄) 또는 기타 여러 문제일 수 있습니다.요점은 NoClassDefFoundError가 반드시 클래스 경로 문제인 것은 아니라는 것입니다.

설명할 코드는 다음과 같습니다. java.lang.NoClassDefFoundError.참조하세요 재러드의 대답 자세한 설명을 위해.

NoClassDefFoundErrorDemo.java

public class NoClassDefFoundErrorDemo {
    public static void main(String[] args) {
        try {
            // The following line would throw ExceptionInInitializerError
            SimpleCalculator calculator1 = new SimpleCalculator();
        } catch (Throwable t) {
            System.out.println(t);
        }
        // The following line would cause NoClassDefFoundError
        SimpleCalculator calculator2 = new SimpleCalculator();
    }

}

SimpleCalculator.java

public class SimpleCalculator {
    static int undefined = 1 / 0;
}

런타임에 발견된 클래스의 호환되지 않는 버전으로 코드를 컴파일할 때 때때로 NoClassDefFound 오류가 발생하는 것을 발견했습니다.내가 기억하는 구체적인 사례는 Apache 축 라이브러리에 관한 것입니다.내 런타임 클래스 경로에는 실제로 두 가지 버전이 있었고 올바른 버전이 아닌 오래되고 호환되지 않는 버전을 선택하여 NoClassDefFound 오류가 발생했습니다.이것은 이와 유사한 명령을 사용하고 있던 명령줄 앱에 있었습니다.

set classpath=%classpath%;axis.jar

다음을 사용하여 적절한 버전을 선택할 수 있었습니다.

set classpath=axis.jar;%classpath%;

Java의 NoClassDefFoundError

정의:

  1. Java Virtual Machine은 컴파일 타임에 사용 가능한 특정 클래스를 런타임에 찾을 수 없습니다.

  2. 컴파일 시간에는 클래스가 있었지만 런타임 중에는 Java 클래스 경로에서 사용할 수 없는 경우입니다.

enter image description here

예:

  1. 클래스는 클래스 경로에 없으며 이를 알 수 있는 확실한 방법은 없지만 여러 번 System.getproperty("java.classpath")를 인쇄해 보면 적어도 얻을 수 있는 거기에서 클래스 경로가 인쇄됩니다. 실제 런타임 클래스 경로에 대한 아이디어.
  2. NoClassDefFoundError의 간단한 예는 클래스가 누락된 JAR 파일에 속하거나 JAR이 클래스 경로에 추가되지 않았거나 때때로 jar의 이름이 내 경우처럼 누군가에 의해 변경된 것입니다. 제 경우에는 동료 중 한 명이 tibco.jar를 tibco_v3.jar로 변경했고 프로그램은 다음과 같습니다. java.lang.NoClassDefFoundError로 실패했는데 무엇이 잘못되었는지 궁금합니다.

  3. 작동할 것으로 생각되는 클래스 경로를 사용하여 명시적으로 -classpath 옵션을 사용하여 실행해 보십시오. 작동한다면 누군가가 Java 클래스 경로를 재정의하고 있다는 확실한 짧은 신호입니다.

  4. JAR 파일에 대한 권한 문제로 인해 Java에서 NoClassDefFoundError가 발생할 수도 있습니다.
  5. XML 구성의 오타로 인해 Java에서 NoClassDefFoundError가 발생할 수도 있습니다.
  6. JApplet의 경우처럼 패키지에 정의된 컴파일된 클래스가 로드하는 동안 동일한 패키지에 존재하지 않으면 Java에서 NoClassDefFoundError가 발생합니다.

가능한 해결책:

  1. 해당 클래스는 Java 클래스 경로에서 사용할 수 없습니다.
  2. J2EE 환경에서 작업하는 경우 여러 클래스 로더 간의 클래스 가시성으로 인해 java.lang.NoClassDefFoundError가 발생할 수도 있습니다. 자세한 내용은 예제 및 시나리오 섹션을 참조하세요.
  3. 로그 파일에서 java.lang.ExceptionInInitializerError를 확인하세요.정적 초기화 실패로 인한 NoClassDefFoundError는 매우 일반적입니다.
  4. NoClassDefFoundError는 java.lang.LinkageError의 하위 클래스이기 때문에 네이티브 라이브러리와 같은 종속성 중 하나를 사용할 수 없는 경우에도 발생할 수 있습니다.
  5. 모든 시작 스크립트는 Classpath 환경 변수를 재정의합니다.
  6. jar 명령을 사용하여 프로그램을 실행 중일 수 있으며 매니페스트 파일의 ClassPath 속성에 클래스가 정의되지 않았습니다.

자원:

NoClassDefFoundError를 해결하는 3가지 방법

java.lang.NoClassDefFoundError 문제 패턴

이것이 최고의 솔루션 지금까지 찾았습니다.

다음과 같은 패키지가 있다고 가정해 보겠습니다. org.mypackage 클래스를 포함:

  • HelloWorld(메인 클래스)
  • 지원 클래스
  • 유틸리티 클래스

이 패키지를 정의하는 파일은 물리적으로 디렉터리 아래에 저장됩니다. D:\myprogram (Windows의 경우) 또는 /home/user/myprogram (리눅스에서).

파일 구조는 다음과 같습니다.enter image description here

Java를 호출할 때 실행할 애플리케이션의 이름을 지정합니다. org.mypackage.HelloWorld.그러나 우리는 또한 패키지를 정의하는 파일과 디렉터리를 찾을 위치를 Java에 알려주어야 합니다.따라서 프로그램을 시작하려면 다음 명령을 사용해야 합니다.enter image description here

나는 사용하고 있었다 스프링 프레임워크 ~와 함께 메이븐 내 프로젝트에서 이 오류를 해결했습니다.

수업에 런타임 오류가 발생했습니다.속성을 정수로 읽고 있었는데 속성 파일에서 값을 읽으면 해당 값이 두 배가 되었습니다.

Spring은 런타임이 실패한 라인에 대한 전체 스택 추적을 제공하지 않았습니다.그것은 단순히 말했다 NoClassDefFoundError.하지만 네이티브 Java 애플리케이션으로 실행했을 때(MVC에서 가져옴) ExceptionInInitializerError 이것이 실제 원인이었고 오류를 추적한 방법이었습니다.

@xli의 답변을 통해 내 코드에서 무엇이 잘못되었을 수 있는지에 대한 통찰력을 얻을 수 있었습니다.

런타임 클래스 로더에 의해 로드된 클래스가 Java 루트로더에 의해 이미 로드된 클래스에 액세스할 수 없는 경우 NoClassFoundError가 발생합니다.서로 다른 클래스 로더가 서로 다른 보안 도메인(java에 따라)에 있기 때문에 jvm은 루트로더가 이미 로드한 클래스가 런타임 로더 주소 공간에서 확인되는 것을 허용하지 않습니다.

'java -javaagent:tracer.jar [YOUR java ARGS]'를 사용하여 프로그램을 실행하세요.

로드된 클래스와 클래스를 로드한 로더 환경을 보여주는 출력을 생성합니다.클래스를 해결할 수 없는 이유를 추적하는 것은 매우 유용합니다.

// ClassLoaderTracer.java
// From: https://blogs.oracle.com/sundararajan/entry/tracing_class_loading_1_5

import java.lang.instrument.*;
import java.security.*;

// manifest.mf
// Premain-Class: ClassLoadTracer

// jar -cvfm tracer.jar manifest.mf ClassLoaderTracer.class

// java -javaagent:tracer.jar  [...]

public class ClassLoadTracer 
{
    public static void premain(String agentArgs, Instrumentation inst) 
    {
        final java.io.PrintStream out = System.out;
        inst.addTransformer(new ClassFileTransformer() {
            public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException {

                String pd = (null == protectionDomain) ? "null" : protectionDomain.getCodeSource().toString();
                out.println(className + " loaded by " + loader + " at " + new java.util.Date() + " in " + pd);

                // dump stack trace of the thread loading class 
                Thread.dumpStack();

                // we just want the original .class bytes to be loaded!
                // we are not instrumenting it...
                return null;
            }
        });
    }
}

특히 당신이 본다면 이것을 읽으십시오 NoClassDefFoundErrors 단위 테스트에서...


많이 볼 수 있는 흥미로운 사례 NoClassDefFoundErrors 다음과 같은 경우입니다.

  1. throwRuntimeException 에서 static 당신 수업의 블록 Example
  2. 가로채세요(또는 그냥 던져지는 것처럼 중요하지 않은 경우). 테스트 케이스)
  3. 이 클래스의 인스턴스를 만들어 보십시오. Example

static class Example {
    static {
        thisThrowsRuntimeException();
    }
}

static class OuterClazz {

    OuterClazz() {
        try {
            new Example();
        } catch (Throwable ignored) { //simulating catching RuntimeException from static block
            // DO NOT DO THIS IN PRODUCTION CODE, THIS IS JUST AN EXAMPLE in StackOverflow
        }

        new Example(); //this throws NoClassDefFoundError
    }
}

NoClassDefError 함께 던져질 것이다 ExceptionInInitializerError 정적 블록에서 RuntimeException.


이것은 볼 때 특히 중요한 경우입니다. NoClassDefFoundErrors 당신의 단위 테스트.

어떤 면에서는 '공유'하고 있습니다. static 테스트 사이의 실행을 차단하지만 초기에는 ExceptionInInitializerError 하나의 테스트 케이스에만 있을 것입니다.문제가 있는 것을 사용하는 첫 번째 것 Example 수업.다음을 사용하는 다른 테스트 케이스 Example 수업은 그냥 던질 것입니다 NoClassDefFoundErrors.

생성된 코드(EMF 등)가 있는 경우 모든 스택 공간을 소비하는 정적 초기화 프로그램이 너무 많을 수 있습니다.

스택 오버플로 질문을 참조하세요. Java 스택 크기를 늘리는 방법은 무엇입니까?.

아래 기술은 여러 번 도움이 되었습니다.

System.out.println(TheNoDefFoundClass.class.getProtectionDomain().getCodeSource().getLocation());

여기서 TheNoDefFoundClass는 프로그램에서 사용하는 동일한 라이브러리의 이전 버전에 대한 선호로 인해 "손실"될 수 있는 클래스입니다.이는 클라이언트 소프트웨어가 자체 클래스 로더와 가장 인기 있는 라이브러리의 수많은 고대 버전으로 무장된 주요 컨테이너에 배포되는 경우에 가장 자주 발생합니다.

모든 모듈에 대해 preDexLibraries를 비활성화하여 문제를 해결했습니다.

dexOptions {
        preDexLibraries false
        ...

NoClassDefFoundError 다음과 같은 경우에도 발생할 수 있습니다. 공전 초기화 프로그램은 런타임에 사용할 수 없는 리소스 번들을 로드하려고 시도합니다. 예를 들어 영향을 받은 클래스가 META-INF 디렉토리가 있지만 거기에 없습니다.잡지 못한다면 NoClassDefFoundError, 때로는 전체 스택 추적을 볼 수 없는 경우도 있습니다.이 문제를 극복하기 위해 일시적으로 catch 대한 조항 Throwable:

try {
    // Statement(s) that cause the affected class to be loaded
} catch (Throwable t) {
    Logger.getLogger("<logger-name>").info("Loading my class went wrong", t);
}

누군가 때문에 여기에 오면 java.lang.NoClassDefFoundError: org/apache/log4j/Logger 내 경우에는 log4j 2를 사용했기 때문에 오류가 발생했지만(그러나 함께 제공되는 모든 파일을 추가하지는 않았습니다) 일부 종속성 라이브러리는 log4j 1을 사용했습니다.해결책은 Log4j 1.x 브리지를 추가하는 것이었습니다.항아리 log4j-1.2-api-<version>.jar log4j 2와 함께 제공됩니다.log4j 2의 추가 정보 이주.

동일한 프로젝트의 서로 다른 체크아웃 사본 2개

내 경우에는 Eclipse가 동일한 프로젝트의 서로 다른 두 복사본을 구별할 수 없다는 것이 문제였습니다.하나는 트렁크(SVN 버전 제어)에 잠겨 있고 다른 하나는 한 번에 한 지점에서 작업하고 있습니다.JUnit 테스트 사례로 작업 복사본에서 한 가지 변경 사항을 시도했습니다. 여기에는 비공개 내부 클래스를 자체적으로 공개 클래스로 추출하는 것이 포함되었으며 작업하는 동안 프로젝트의 다른 복사본을 열어 다른 항목을 살펴보았습니다. 변경이 필요한 코드 부분.어느 시점에서, NoClassDefFoundError 개인 내부 클래스가 없다고 불평하는 팝업이 나타났습니다.스택 추적을 두 번 클릭하면 잘못된 프로젝트 복사본의 소스 파일이 표시됩니다.

프로젝트의 트렁크 복사본을 닫고 테스트 케이스를 다시 실행하면 문제가 해결되었습니다.

이 오류는 선택 취소로 인해 발생할 수 있습니다. 자바 버전 요구 사항.

내 경우에는 유명한 오픈 소스 프로젝트를 빌드하는 동안 다음을 사용하여 Java 9에서 Java 8로 전환하여 이 오류를 해결할 수 있었습니다. SDKMAN!.

sdk list java
sdk install java 8u152-zulu
sdk use java 8u152-zulu

그런 다음 아래 설명에 따라 새로 설치를 수행합니다.


사용할 때 메이븐 빌드 도구로서 다음을 수행하는 것이 때때로 도움이 되며 일반적으로 만족스럽습니다. 깨끗한 '설치' 빌드 테스트가 비활성화된 상태에서.

mvn clean install -DskipTests

이제 그 모든 것 빌드 및 설치가 완료되었으면 계속해서 테스트를 실행할 수 있습니다.

mvn test

내 프로젝트의 Java 빌드 경로에 있는 "주문 및 내보내기" 탭에서 클래스를 내보내지 않았을 때 NoClassDefFound 오류가 발생했습니다.프로젝트의 빌드 경로에 추가하는 종속성의 "주문 및 내보내기" 탭에 확인 표시를 했는지 확인하세요.보다 이클립스 경고:XXXXXXXXXXXX.jar은 내보내거나 게시할 수 없습니다.런타임 ClassNotFoundException이 발생할 수 있음.

Java가 런타임에서 클래스 A를 찾을 수 없습니다.클래스 A는 다른 작업공간의 Maven 프로젝트 ArtClient에 있었습니다.그래서 ArtClient를 Eclipse 프로젝트로 가져왔습니다.내 프로젝트 중 두 개는 ArtClient를 종속성으로 사용하고 있었습니다.이러한 항목에 대한 프로젝트 참조로 라이브러리 참조를 변경했습니다(빌드 경로 -> 빌드 경로 구성).

그리고 문제는 사라졌습니다.

나도 같은 문제가 있었고 여러 시간 동안 재고가있었습니다.

해결책을 찾았습니다.제 경우에는 그 때문에 정의된 static 메소드가 있었습니다.JVM은 해당 클래스의 다른 객체를 생성할 수 없습니다.

예를 들어,

private static HttpHost proxy = new HttpHost(proxyHost, Integer.valueOf(proxyPort), "http");

SRC 라이브러리에서 두 개의 파일을 제거한 후 이 메시지를 받았고, 해당 파일을 다시 가져왔을 때 이 오류 메시지가 계속 나타났습니다.

내 해결책은 다음과 같습니다.이클립스를 다시 시작하세요.그 이후로 나는 이 메시지를 다시는 보지 못했습니다 :-)

이것이 일치하는지 확인하십시오. module:app 그리고 module:lib:

android {
    compileSdkVersion 23
    buildToolsVersion '22.0.1'
    packagingOptions {
    }

    defaultConfig {
        minSdkVersion 17
        targetSdkVersion 23
        versionCode 11
        versionName "2.1"
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top