개요

JRE (Java Runtime Environment)를 포함하여 컴파일러, 디버거, 프로파일링 도구 등 개발 및 관리에 필요한 도구 모음이다. 컴파일 시점의 JDK 버전과 실행 시점의 JRE 버전이 어긋나면 실무에서 흔히 겪는 버전 호환성 문제로 이어진다.

핵심 개념

  • 용어 1: JRE - 자바 애플리케이션을 실행하기 위한 핵심 환경만 포함한다. JVM과 핵심 라이브러리로 구성되며, 컴파일러 같은 개발 도구는 포함하지 않는다.
  • 용어 2: 클래스 파일 버전(Major/Minor Version) - .class 파일 헤더에 기록되는 값으로, 어떤 JDK 버전으로 컴파일됐는지를 나타낸다. JVM은 자신이 인식하는 버전보다 높은 클래스 파일을 실행할 수 없어, 이 값이 JDK/JRE 버전 호환성 문제의 실제 판단 기준이 된다.

상세 내용

개발 환경(상위 JDK 컴파일) -> 운영 환경(하위 JRE 실행)

  1. UnsupportedClassVersionError 발생
    • 상위 JDK 컴파일러로 빌드된 .class 파일의 마이너/메이저 버전 번호는 하위 JRE에서 인식하지 못한다. (예: Java 17 JDK로 빌드된 클래스를 Java 11 JRE에서 실행시키면 예외 발생)
  2. 새로운 API 및 바이트코드 미지원
    • 컴파일 시 Target/Release 옵션을 상위로 지정했다면, 하위 JRE 런타임에 존재하지 않는 API를 호출하게 되어 runtime crash가 발생한다.
1
2
3
4
5
6
$ javac --release 17 Main.java   # JDK 17로 컴파일 (class file version 61)
$ java -version # 배포 서버의 실행 환경은 JRE 11 (class file version 55)
$ java Main
java.lang.UnsupportedClassVersionError: Main has been compiled by a more
recent version of the Java Runtime (class file version 61.0), this version
of the Java Runtime only recognizes class file versions up to 55.0

개발 환경(하위 JDK 컴파일) -> 운영 환경(상위 JRE 실행)

구분 설명
기본 원칙 JVM은 하위 호환성을 보장하므로, 낮은 class file version으로 컴파일된 바이트코드는 상위 JRE에서 대체로 문제없이 실행된다.
예외 상황 바이트코드 형식 자체는 호환되지만, 컴파일 당시 사용한 API가 상위 버전에서 제거되거나 모듈 경계(JPMS)에 막혀 런타임에 ClassNotFoundException, NoClassDefFoundError가 발생할 수 있다. (예: Java 11부터 javax.xml.bind, java.xml.ws 등 Java EE 관련 모듈이 기본 런타임에서 제거됨)
실무 권장 배포 대상 JRE 버전이 다양하다면 "하위 버전은 항상 안전하다"고 단정하기보다, --release 옵션으로 실제 지원해야 하는 가장 낮은 버전을 명시적으로 타깃해 컴파일하는 편이 안전하다.

정리

Oracle Java 11 이후부터는 독립된 JRE 배포가 중단되었다. 경량화 실행 환경이 필요한 경우 jlink 등을 통해 필요한 모듈만 추출하여 사용자 정의 JRE를 직접 생성하는 방식이 표준이다. 다만 이 글에서 다룬 것처럼 JDK/JRE 버전 호환은 "상위 컴파일 → 하위 실행은 위험, 하위 컴파일 → 상위 실행은 안전"이라는 이분법만으로는 부족하고, 실행 시점에 실제로 필요한 API가 그 버전에 남아있는지까지 함께 확인해야 한다.