에듀테크 프로젝트 대시보드
JIT 컴파일 (Just-In-Time)
같은 코드인데도 프로그램이 오래 돌수록 빨라진 경험이 있나요? 자바스크립트 엔진(V8)·JVM· 파이썬(PyPy) 같은 런타임은 자주 실행되는 코드(핫스팟)를 실행 도중에 기계어로 번역합니다. 이것이 JIT(Just-In-Time) 컴파일입니다. 아래에서 루프를 직접 돌려 "워밍업"이 일어나는 순간을 관찰해 보세요.
// 배열 원소를 모두 더하는 함수 function sumArray(arr) { let total = 0; for (let i = 0; i < arr.length; i++) total += arr[i]; // 인라인 캐시가 붙는 지점 return total; } // 루프에서 sumArray()를 반복 호출
total += arr[i] 한 줄에도 "arr이 진짜 배열인가?",
"원소가 정수인가?" 같은 확인이 숨어 있습니다. 매번 확인하면 느리죠. JIT은 처음 본
타입을 기억(캐시)해 두고, 다음부터는 "지난번과 같지?"만 검사합니다.
엔진이 전체 조회 경로를 밟는다: arr의 히든클래스 확인 → 요소 종류(정수 배열)
기록 → "이 자리엔 정수 배열이 온다"고 캐시에 못박음.
"이번에도 정수 배열?" 포인터 1회 비교로 끝. 최적화 JIT은 아예 경계검사·박싱까지
제거하고 load + add 두 명령으로 압축.
어떨 땐 정수, 어떨 땐 실수, 어떨 땐 문자열이 들어오면 캐시에 여러 경우가 쌓여 분기가 늘어난다. 4가지 넘게 섞이면 캐시를 포기(megamorphic)하고 느린 경로로.
"정수만 온다"고 가정하고 만든 기계어에 문자열이 들어오면? 최적화 코드를 버리고 인터프리터로 되돌아가 다시 관찰 시작. 위 데모의 💥 버튼이 이것.
| 방식 | 번역 시점 | 장점 | 약점 | 예 |
|---|---|---|---|---|
| AOT 컴파일 (Ahead-Of-Time) |
실행 전 전체를 기계어로 | 시작 즉시 최고 속도, 런타임 오버헤드 없음 | 플랫폼별 빌드 필요, 런타임 정보(실제 입력 타입)를 못 씀 | C·C++·Rust·Go |
| 인터프리터 | 실행 중 한 줄씩 해석 | 즉시 시작, 이식성 최고, 메모리 적음 | 반복 코드도 매번 해석 → 느림 | CPython, 초기 JS |
| JIT 컴파일 | 실행 중 핫스팟만 기계어로 | 실제 실행 패턴에 맞춘 최적화(타입 추측·인라인), 인터프리터보다 10~100× | 워밍업 지연, 컴파일 스레드·메모리 비용, deopt 위험 | V8, JVM HotSpot, PyPy, .NET |
"이 함수가 N번 호출됐다" → 함수 전체를 컴파일. JVM HotSpot, V8이 이 방식. 호출 카운터 + 루프 백엣지 카운터로 핫 판정.
"이 루프가 뜨겁다" → 한 번 도는 동안의 실제 실행 경로(trace)를 그대로 기록해 직선 코드로 컴파일. 자주 안 도는 분기는 "가드"만 남김. PyPy·초기 TraceMonkey.