Java.Lang.VerifyError: 피연산자 스택의 잘못된 유형

Suraj P 2023년10월12일
  1. Java에서 java.lang.VerifyError 이해
  2. Java에서 java.lang.VerifyError의 예
Java.Lang.VerifyError: 피연산자 스택의 잘못된 유형

이 기사에서는 Java의 java.lang.VerifyError에 대해 알아봅니다.

Java에서 java.lang.VerifyError 이해

java.lang.VerifyError는 바이트코드 검증 과정에서 JVM(Java Virtual Machine)에서 발생하는 오류입니다. 이 오류는 JVM이 클래스 또는 메소드의 바이트 코드가 유효하지 않거나 특정 제약 조건을 위반함을 감지할 때 발생합니다.

java.lang.VerifyError가 발생할 수 있는 몇 가지 이유가 있습니다.

  1. 호환되지 않는 클래스 버전: 클래스를 실행하려는 JVM 버전과 다른 버전의 Java 컴파일러로 클래스를 컴파일하는 경우 VerifyError가 발생할 수 있습니다. 이는 클래스가 최신 버전의 Java로 빌드되었지만 이전 JVM에서 실행되는 경우에 발생할 수 있습니다.
  2. 호환되지 않는 라이브러리 버전: 클래스가 컴파일된 버전과 다른 버전의 라이브러리에 의존하는 경우 VerifyError가 발생할 수 있습니다.
  3. opcode의 불법 사용: 클래스 또는 메서드가 불법적이거나 지원되지 않는 방식으로 opcode를 사용하는 경우 VerifyError가 발생할 수 있습니다.
  4. 잘못된 클래스 파일 형식: 클래스 파일이 손상되었거나 형식이 잘못된 경우 VerifyError가 발생할 수 있습니다.
  5. final 키워드의 잘못된 사용: final 변수가 초기화된 후 새 값이 할당되면 VerifyError가 발생할 수 있습니다.
  6. 다른 classloader가 클래스를 로드할 때 리플렉션을 사용하여 클래스의 전용 필드/메소드에 대한 액세스 가능성을 변경합니다.

이 오류를 수정하려면 문제의 원인을 찾아 수정해야 합니다. 여기에는 호환 가능한 버전의 Java 컴파일러로 클래스를 다시 컴파일하거나, 라이브러리 버전을 업데이트하거나, opcode의 불법 사용을 제거하는 작업이 포함될 수 있습니다.

리플렉션 사용으로 인한 오류인 경우 다른 클래스 로더에 의해 로드된 클래스의 개인 필드/메소드에 대한 액세스 가능성을 변경하지 않음으로써 오류를 피할 수 있습니다.

일반적으로 사용 중인 Java 컴파일러 및 라이브러리의 버전을 알고 있고 호환성을 보장하기 위해 다른 버전의 JVM으로 코드를 테스트하는 것이 좋습니다. 또한 java.lang.VerifyError와 같은 오류를 방지하려면 클래스 파일과 라이브러리를 최신 상태로 양호한 상태로 유지하는 것이 중요합니다.

java.lang.VerifyError는 런타임 오류이며 컴파일 시간 오류인 java.lang.VerificationError와 다릅니다.

Java에서 java.lang.VerifyError의 예

더 잘 이해하기 위해 예를 살펴보겠습니다.

예제 1: A.javaB.java라는 두 개의 Java 파일을 만듭니다.

A.java 파일:

public class A {
  public A() {
    System.out.println("Instance of A is created");
  }
}

B.java 파일:

public class B extends A {
  public B() {
    super();
    System.out.println("Instance of B is created");
  }

  public static void main(String[] args) {
    B obj = new B();
  }
}

이제 파일을 컴파일합니다.

javac A.java
javac B.java

두 파일 모두 오류 없이 제대로 컴파일됩니다.

그러나 class A의 정의를 final로 변경한 다음 class A만 다시 컴파일한 다음 class Bmain 메서드를 실행하면 다음 오류가 발생합니다.

Exception in thread "main" java.lang.VerifyError: Cannot inherit from final class
    at java.lang.ClassLoader.defineClass1(Native Method)
    at java.lang.ClassLoader.defineClass(ClassLoader.java:760)
     ......
     ......

이 오류는 클래스 A의 정의를 변경했는데 클래스 B클래스 A의 이전 버전으로 실행되었기 때문에 발생합니다.

예 2:

세 개의 Java 파일 A.java, B.javaC.java를 만듭니다. class Bclass A를 상속하고 class C에는 main 메서드가 포함됩니다.

A.java 파일:

public class A {
  public A() {
    System.out.println("Class A instance is created");
  }

  public void print() {
    System.out.println("A::print()");
  }
}

B.java 파일:

public class B extends A {
  public B() {
    super();
    System.out.println("Class B instance is created");
  }

  public void print() {
    System.out.println("B::print()");
  }
}

‘C.java’ 파일:

public class C {
  public static void _print_(A obj) {
    obj.print();
  }

  public static void main(String[] args) {
    B b = new B();
    C._print_(b);
  }
}

Java 파일을 별도로 컴파일한 다음 C.java를 실행합니다.

javac A.java
javac B.java
javac C.java
java C

실행 결과는 다음과 같습니다.

Class A instance is created
Class B instance is created
B::print()

이제 class A를 확장하지 않도록 class B의 정의를 변경한 다음 B.java를 다시 컴파일한 다음 class C를 실행하면 다음 오류가 발생합니다.

Exception in thread "main" java.lang.VerifyError: Bad type on operand stack
Exception Details:
  ....
  ....

여기서도 클래스 B의 정의를 변경했기 때문에 오류가 발생하지만 클래스 C클래스 B의 이전 버전으로 실행됩니다.

작가: Suraj P
Suraj P avatar Suraj P avatar

A technophile and a Big Data developer by passion. Loves developing advance C++ and Java applications in free time works as SME at Chegg where I help students with there doubts and assignments in the field of Computer Science.

LinkedIn GitHub

관련 문장 - Java Error