[Java 기본 원리] Java 실행 과정과 컴파일러의 모든 것(AOT vs JIT)
Java 애플리케이션은 소스코드 작성부터 실행까지 컴파일과 실행 엔진을 통한 복잡한 과정을 거친다. 자바는 정적, 동적 컴파일 방식 둘 다 사용한다는게 핵심이다.
Java 실행 과정 💡
-
소스코드 컴파일
-
.java
파일 작성 -
javac
컴파일러로 컴파일하여 바이트코드(.class
) 생성
-
-
JVM 실행 단계
-
클래스 로더가 바이트코드(
.class
)를 JVM 런타임 데이터 영역(메모리 영역)에 로드 -
실행 엔진을 통한 코드 실행
-
실행 엔진 방식1: 인터프리터 방식
-
실행 엔진 방식2: JIT 컴파일러 방식
-
-
-
실행 엔진 자세히 (심화)
-
JVM은 먼저, 인터프리터 방식으로 바이트코드(
.class
) 실행 -
실행패턴에 따라 JIT컴파일러로 바이트 코드를 네이티브 코드로 변환하는 최적화
이걸 왜 하냐?? -> 속도 문제 해결을 위한 JIT컴파일러-
인터프리터 방식은 한 라인씩 읽고 실행하므로 반복문의 경우 매번 읽고, 번역 -> 속도 느림
-
바이트코드(
.class
) 역시 기계어(0,1,0,1…)로 변환되어야 하기 때문! -
따라서 자주 실행되는 바이트 코드 영역을 런타임 중에 기계어로 컴파일하여 사용(캐싱,동적)
-
즉, Java는
정적 컴파일 방식
과동적 컴파일 방식
을 함께 사용
-
-
JIT컴파일된 네이티브 코드를 최종적으로 함께 실행
-
컴파일러 비교 - AOT vs JIT 🔍
둘 다 바이트코드(JVM용 언어=.class
)를 기계 언어로 변경하는건 동일!
단, 동적이냐 정적이냐 차이이다.
JIT(Just-In-Time) 컴파일러
이름에서 알 수 있듯이 동적 컴파일 방식이다.
- 런타임 중 필요한 부분만 컴파일
- 즉, C나 C++처럼 프로그램을 실행하기 전에 처음 한 번 컴파일하는 대신, 프로그램을 실행하는 시점에서 필요한 부분을 즉석으로 컴파일하는 방식을 말한다.
- HotSpotVM (JVM 구현중 하나)으로 최적화를 진행!
- 동적 기능 지원 (리플렉션, JNI)
AOT(Ahead-Of-Time) 컴파일러
이름에서 알 수 있듯이 정적 컴파일 방식이다.
- 실행 전 전체 코드 컴파일
- 즉, C나 C++처럼 프로그램을 실행하기 전에 처음 한 번 컴파일
- GraalVM (JVM 구현중 하나) 사용
- AOT는 컴파일 한번이니 당연히 더 빠르지만, 아직까지는 보완할 점이 많다. -> 플랫폼 종속적, 동적기능 부족
- 런타임에 호출할 수 있는 응용 프로그램의 모든 바이트 코드와 종속성을 미리 알아야 한다. (종속성의 문제)
- JNI, Java Reflection, 동적 프록시 개체, 클래스 경로 리소스같은 동적기능이 지원되지 않는다.
실무 적용 전략
기본적으로 JIT 컴파일러만 생각하고 개발하면 충분하다. 사실 AOT 방식은 좀 더 발전해야 하기 때문이다.
그래도 함께 활용하고 싶다면 아래 전략을 추천한다.
개발 환경 : JIT 컴파일러 사용
- 빠른 수정 반영
- 동적 기능 활용
프로덕션(배포) 환경 : AOT 컴파일러 사용
- 향상된 런타임 성능
- 최적화된 실행 속도
댓글남기기