JIT 컴파일링 — 학습 안내서

발행: (2026년 6월 9일 AM 10:55 GMT+9)
7 분 소요
원문: Dev.to

출처: Dev.to

배울 내용:

  • JVM이 무엇을 언제 컴파일할지 결정하는 방식

  • C1과 C2의 실제 차이점

  • Code Cache가 무엇이며 왜 성능을 떨어뜨릴 수 있는지

  • GraalVM: JIT vs Native Image

  • Project Leyden: Java 25가 워밍업 문제를 어떻게 해결했는지

    목차

1. 원래 문제

2. Just‑In‑Time Compilation

3. 두 컴파일러: C1과 C2

4. Code Cache

5. GraalVM

6. Project Leyden

7. 워밍업에 대한 고민을 언제 멈출까

8. 타임라인 및 실행 요약

9. GraalVM vs 비 GraalVM — 실제 데이터 분석

왜 Java는 느렸고, 어떻게 해결했는가

모든 Java 개발자가 겪은 장면

💡 메서드 성능을 측정했을 때 처음에 200 ms가 나왔다.

30 초 뒤 다시 측정하면 8 ms가 나왔다.

무슨 일이 일어난 걸까? 애플리케이션이 “워밍업”되고 있었다.

이 현상에는 이름이 있고 메커니즘이 있으며, Java 25부터는 최종 해결책이 있다.

Java는 소스 코드(.java)를 바이트코드(.class)라는 중간 형식으로 컴파일한다. 이 바이트코드는 플랫폼에 독립적이며, JVM은 어느 머신이든 이 바이트코드를 해석한다. 바로 유명한 write once, run anywhere다.

하지만 해석은 명령어 하나하나를 실행하므로 느리다. 1996년에는 Java가 C보다 10~20배 느렸다.

접근 방식 비교

접근 방식이식성성능예시
네이티브 컴파일❌ OS별 바이너리⭐⭐⭐⭐⭐ 최고C / C++
순수 인터프리터✅ 범용 바이트코드⭐ 낮음Java 1.0 (1996)
JIT — 하이브리드✅ 범용 바이트코드⭐⭐⭐⭐⭐ 높음Java 1.3+ (2000)
AOT Cache (Leyden)✅ 범용 바이트코드⭐⭐⭐⭐⭐ 높음 + 빠른 시작Java 24+ (2024)

💬 JIT을 떠올리게 만든 질문: “JVM이 실행 중에 학습해서 어떤 부분을 네이티브 코드로 컴파일해야 할지 스스로 판단할 수 있다면 어떨까? 이때 이식성은 포기하고 싶지 않다.”

섹션 2 — Just‑In‑Time Compilation

JVM이 실시간으로 관찰·결정·컴파일하는 과정

JIT은 HotSpot JVM이 실행 중인 코드를 관찰하고, 자주 호출되는 구간(hot spot)을 발견하면 별도 스레드에서 네이티브 머신 코드로 컴파일한다. 이 과정은 애플리케이션을 멈추게 하지 않는다.

JVM에서 메서드가 거치는 전체 과정

1단계 — 인터프리터 실행 (Tier 0)

JVM은 바이트코드를 한 줄씩 해석한다. 느리지만 즉시 실행 가능하다. 동시에 메서드당 두 개의 카운터가 증가한다:

  • Method invocation count — 메서드가 호출된 횟수

  • Loop back‑edge count — 메서드 내부 루프가 반복된 횟수

    2단계 — C1에 의한 빠른 컴파일 및 프로파일링 (Tier 1–3)

카운터가 Tier3CompileThreshold(기본값: 2 000 호출)를 초과하면 메서드가 JIT 큐에 들어간다. C1 컴파일러가 빠르게 네이티브 코드를 생성하고 동시에 행동 데이터를 수집한다. 애플리케이션은 이미 빨라졌지만 아직 최적은 아니다.

3단계 — C2에 의한 공격적 최적화 (Tier 4)

메서드가 Tier4CompileThreshold(기본값: 15 000 호출)에 도달하면 C2가 작동한다. C2는 C1이 수집한 프로파일을 활용해 인라이닝, 디버추얼라이제이션, 이스케이프 분석 등 실시간 관찰 없이는 적용할 수 없는 최적화를 수행한다.

4단계 — Code Cache에 저장

C

0 조회
Back to Blog

관련 글

더 보기 »

Eidentic 소개

Today we're releasing Eidentic, an open-source TypeScript SDK for building AI agents with self-improving memory and the production fundamentals built in — not b...

Typescript의 타입

Introdução Tipos são uma forma de definir a “forma” ou o contrato dos dados que estamos usando no código. Pensando em Javascript puro, ele é dinâmico: você pode...