JIT Compiler는 런타임 시 바이트 코드를 원시 시스템 코드로 컴파일하여 Java 애플리케이션의 성능을 향상시키는 런타임 환경의 컴포넌트입니다.
- 실행 엔진의 구성 요소
- 프로그램 실행 중 자주 호출되는 메서드나 반복적으로 실행되는 루프를 기계어로 컴파일
- 컴파일된 코드들은 Code Cache에 저장
- 이후 인터프리터가 동일한 바이트코드를 반복하여 실행하는 대신 컴파일된 기계어를 실행
INFO
Java 6에서는 c1과 c2 컴파일러 중 하나를 선택해야 했으며 이후 Java 8부터는 계층형 컴파일 방식이 기본 동작이 되었다.
계층형 컴파일
프로그램 실행 초기에는 빠른 시작을 위해 가벼운 컴파일을 적용하고, 자주 쓰이는 코드는 나중에 강력한 최적화 컴파일로 다시 처리하는 방식이다. 이 구조는 주로 인터프리터, C1 컴파일러(클라이언트), C2 컴파일러(서버) 단계로 나뉜다.

단순화하면 다음과 같은 순서이다.
인터프리터 → C1 컴파일 → C2 컴파일
c1 클라이언트 컴파일러 (Client Compiler)
- 코드 최적화는 덜하지만 즉시 시작되는 속도는 빠름
- 즉시 실행되는 데스크톱 애플리케이션 등에 적합함
c2 서버 컴파일러 (Server Compiler)
- 즉시 시작되는 속도는 느리지만 최적화는 많이 되어 warm-up 후에는 빠름
- 장기 실행되는 서버 애플리케이션 등에 적합함
JIT 컴파일러가 자주 사용되는 코드를 어떻게 판단하나요?
JIT 컴파일러는 런타임 중에 메서드의 호출 횟수를 프로파일링하여 자주 사용되는 코드를 판단합니다. 구체적으로 c1 컴파일러는 메서드 호출 횟수가 약 2,000회를 넘으면 제한된 수준으로 최적화하여 컴파일하고, c2 컴파일러는 약 15,000회를 넘으면 더 높은 수준으로 최적화하여 컴파일합니다.
https://www.youtube.com/watch?v=o8RCZapn7SE
JIT 코드 캐시가 꽉 차면 어떻게 되나요?
코드 캐시가 꽉 차면 JIT 컴파일러는 더 이상 새로운 코드를 컴파일하지 못합니다. 새로운 코드들은 인터프리터 방식으로 전환하여 바이트코드를 한줄씩 해석하여 실행합니다. 이로 인해 컴파일된 기계어를 사용할 수 없게 되므로 애플리케이션의 실행 속도가 느려지는 성능저하가 발생합니다.
https://www.youtube.com/watch?v=WcTFaa3hkIk
출처 및 참고자료
https://mangkyu.tistory.com/343
https://advancedweb.hu/jvm-jit-optimization-techniques/