본문으로 건너뛰기
Kreath Archive
TechProjectsBooksAbout
TechProjectsBooksAbout

내비게이션

  • Tech
  • Projects
  • Books
  • About
  • Tags

카테고리

  • AI / ML
  • 웹 개발
  • 프로그래밍
  • 개발 도구

연결

  • GitHub
  • Email
  • RSS
© 2026 Kreath Archive. All rights reserved.Built with Next.js + MDX
홈TechProjectsBooksAbout
//
  1. 홈
  2. 테크
  3. 8장: 실험적 JIT 컴파일러의 원리와 가능성
2026년 1월 30일·프로그래밍·

8장: 실험적 JIT 컴파일러의 원리와 가능성

Python 3.13에 도입된 실험적 JIT 컴파일러를 분석합니다. copy-and-patch 기법의 원리, Tier 2 최적화 파이프라인, 빌드와 활성화 방법, 성능 벤치마크를 다룹니다.

17분364자11개 섹션
pythontypescriptperformancedevtoolsconcurrency
공유
python-trends8 / 13
12345678910111213
이전7장: Free-threaded Python - GIL 제거의 시작다음9장: uv - 차세대 Python 패키지 매니저

Python에 JIT 컴파일러가 필요한 이유

JIT(Just-In-Time) 컴파일러는 프로그램이 실행되는 동안 바이트코드를 기계어로 변환하는 기술입니다. Java의 HotSpot, JavaScript의 V8, C#의 .NET JIT가 대표적입니다. 이들 언어의 성능이 크게 향상된 핵심 요인이 JIT 컴파일러입니다.

Python은 오랫동안 인터프리터 방식으로만 실행되었습니다. PyPy가 JIT 컴파일러를 통해 CPython 대비 수배의 성능을 달성했지만, CPython 자체에 JIT가 도입된 것은 3.13이 처음입니다.

CPython의 실행 모델

CPython이 Python 코드를 실행하는 과정을 이해하면, JIT가 어디에 개입하는지 알 수 있습니다.

CPython 실행 과정
text
Python 소스 코드
    |
    v
[컴파일러] --> 바이트코드 (.pyc)
    |
    v
[Tier 1 인터프리터] --> 바이트코드 실행
    |
    v (자주 실행되는 코드 감지)
[Tier 2 최적화기] --> Tier 2 IR (중간 표현)
    |
    v
[JIT 컴파일러] --> 기계어 (선택적)

Python 3.11에서 도입된 특수화 적응 인터프리터가 Tier 1에 해당하고, 3.13의 JIT는 Tier 2 최적화 파이프라인의 마지막 단계입니다.

Copy-and-Patch: JIT의 핵심 기법

Python 3.13의 JIT는 copy-and-patch라는 비교적 새로운 컴파일 기법을 사용합니다. 이 기법은 Haoran Xu와 Fredrik Kjolstad가 2021년에 발표한 논문에서 제안되었습니다.

전통적 JIT vs Copy-and-Patch

전통적 JIT 컴파일러는 IR(중간 표현)을 분석하고, 레지스터를 할당하며, 최적화를 적용한 후 기계어를 생성합니다. 이 과정은 복잡하고 구현 비용이 높습니다.

copy-and-patch는 이와 다른 접근 방식을 취합니다.

copy-and-patch 동작 원리
text
빌드 타임:
  1. 각 바이트코드 연산에 대한 C 코드를 LLVM으로 컴파일
  2. 생성된 기계어를 "스텐실(stencil)"로 저장
  3. 스텐실에서 패치가 필요한 위치(구멍)를 기록
 
런타임:
  1. 실행할 바이트코드 시퀀스 결정
  2. 해당 스텐실들을 메모리에 복사 (copy)
  3. 실제 값으로 구멍을 채움 (patch)
  4. 생성된 기계어를 실행

이 접근 방식의 장점은 명확합니다.

첫째, 복잡한 레지스터 할당과 명령어 선택을 LLVM에 위임합니다. 빌드 타임에 이미 최적의 기계어가 준비되어 있습니다.

둘째, 런타임에는 메모리 복사와 간단한 패치만 수행하므로 컴파일 지연이 최소화됩니다.

셋째, 구현 복잡도가 전통적 JIT에 비해 크게 낮습니다.

스텐실의 구조

스텐실 예시 (개념적)
text
스텐실: BINARY_ADD_INT
  기계어: [mov rax, HOLE_1]  # 첫 번째 피연산자
         [mov rbx, HOLE_2]  # 두 번째 피연산자
         [add rax, rbx]     # 더하기
         [mov HOLE_3, rax]  # 결과 저장
         [jmp HOLE_4]       # 다음 스텐실로 점프
 
패치:
  HOLE_1 -> 실제 피연산자 1의 주소
  HOLE_2 -> 실제 피연산자 2의 주소
  HOLE_3 -> 결과 저장 위치
  HOLE_4 -> 다음 스텐실의 주소

Tier 2 최적화 파이프라인

JIT 컴파일러가 기계어를 생성하기 전에, Tier 2 최적화기가 중간 표현(IR)을 최적화합니다. 이 단계는 JIT 활성화 여부와 관계없이 Python 3.13에서 동작합니다.

핫 코드 감지

CPython은 반복문의 역방향 점프(backward jump)를 모니터링하여 "핫 코드(hot code)"를 감지합니다. 특정 반복문이 충분히 자주 실행되면, 해당 바이트코드를 Tier 2 IR로 변환합니다.

Tier 2 최적화 과정
text
1. 핫 코드 감지 (카운터 기반)
2. 바이트코드 -> Tier 2 IR 변환 (트레이싱)
3. 상수 전파 (constant propagation)
4. 데드 코드 제거 (dead code elimination)
5. 타입 특수화 (type specialization)
6. [JIT 활성 시] IR -> 기계어 변환 (copy-and-patch)

최적화 예시

최적화 대상 코드
python
def sum_squares(n: int) -> int:
    total = 0
    for i in range(n):
        total += i * i
    return total

Tier 2 최적화기는 이 코드에서 다음과 같은 최적화를 적용합니다.

Tier 2 최적화 적용
text
1. range(n)이 int 이터레이터임을 확인 -> FOR_ITER 특수화
2. i가 항상 int임을 확인 -> BINARY_MULTIPLY 특수화
3. total이 항상 int임을 확인 -> BINARY_ADD 특수화
4. 타입 가드(type guard) 삽입: 가정이 깨지면 Tier 1로 폴백

JIT 빌드와 활성화

빌드 요건

JIT 컴파일러를 활성화하려면 CPython을 소스에서 빌드해야 합니다. 빌드 시 LLVM이 필요합니다.

JIT 활성 빌드
bash
# 빌드 의존성 설치
# macOS
brew install llvm
 
# Ubuntu/Debian
sudo apt install llvm-18
 
# CPython 빌드
./configure --enable-experimental-jit
make -j$(nproc)
make install

JIT 활성화 옵션

--enable-experimental-jit 옵션은 여러 모드를 지원합니다.

JIT 활성화 옵션
bash
# JIT 빌드 + 기본 활성화
./configure --enable-experimental-jit
 
# JIT 빌드 + 기본 비활성화 (환경 변수로 활성화)
./configure --enable-experimental-jit=yes-off
 
# 런타임에 JIT 활성화 (yes-off 모드에서)
PYTHON_JIT=1 python3.13 script.py
Info

공식 배포판(python.org에서 다운로드하는 설치 프로그램)에는 JIT가 포함되어 있지 않습니다. JIT를 사용하려면 소스에서 직접 빌드해야 합니다.

현재 성능과 한계

벤치마크 결과

Python 3.13의 JIT는 초기 단계이며, 성능 향상은 제한적입니다.

pyperformance 벤치마크 결과
text
JIT 없음 (Tier 2 인터프리터만): 기준
JIT 활성화: 약 2~5% 향상
 
코드 패턴별 차이:
  수치 연산 루프:  5~9% 향상
  문자열 처리:    1~3% 향상
  객체 생성/소멸: 0~2% 향상
  I/O 중심 코드:  0% (JIT 대상이 아님)

왜 아직 효과가 적은가

현재 JIT의 효과가 제한적인 이유는 다음과 같습니다.

현재 JIT의 한계
text
1. 최적화 범위 제한
   - 함수 내 루프만 대상
   - 함수 간 인라인화 미지원
   
2. 스텐실 최적화 수준
   - 개별 바이트코드 단위의 스텐실
   - 여러 연산을 하나로 합치는 최적화 미적용
 
3. 탈최적화 비용
   - 타입 가드 실패 시 Tier 1로 폴백
   - 폴백 경로의 오버헤드
 
4. 메모리 사용량
   - 기계어 코드를 메모리에 유지
   - 스텐실 테이블 저장 비용

JIT의 미래 가능성

현재 JIT의 성능 향상이 작다고 해서 그 가치가 없는 것은 아닙니다. JIT 인프라가 마련됨으로써 향후 다음과 같은 최적화가 가능해집니다.

예상되는 향후 최적화

향후 JIT 최적화 방향
text
1. 함수 인라인화 (Function Inlining)
   - 작은 함수를 호출자에 직접 삽입
   - 함수 호출 오버헤드 제거
 
2. 탈출 분석 (Escape Analysis)
   - 함수 밖으로 나가지 않는 객체를 스택에 할당
   - 힙 할당과 가비지 컬렉션 비용 감소
 
3. 루프 최적화
   - 루프 언롤링 (loop unrolling)
   - 루프 불변 코드 이동 (loop invariant code motion)
 
4. 스텐실 슈퍼 최적화
   - 연속된 스텐실을 하나의 최적화된 코드로 합침
   - 불필요한 레지스터 이동 제거

PyPy와의 비교

CPython JIT vs PyPy JIT
text
CPython JIT (3.13):
  방식: copy-and-patch
  성숙도: 초기 (실험적)
  성능 향상: 2~5%
  호환성: CPython 완전 호환
  C 확장: 완전 호환
 
PyPy JIT:
  방식: 트레이싱 JIT
  성숙도: 성숙 (10년 이상)
  성능 향상: 3~10배
  호환성: 대부분 호환
  C 확장: 제한적 (cpyext 필요)

PyPy의 JIT가 훨씬 성숙하고 성능이 좋지만, CPython JIT의 장점은 CPython과의 완전한 호환성입니다. C 확장 라이브러리(NumPy, pandas 등)를 문제 없이 사용할 수 있으며, 기존 CPython의 모든 기능을 그대로 유지합니다.

dis 모듈로 최적화 확인

Python의 dis 모듈을 사용하면 바이트코드를 확인할 수 있습니다. 3.13에서는 Tier 2 IR도 확인할 수 있습니다.

바이트코드 분석
python
import dis
 
def add(a, b):
    return a + b
 
# Tier 1 바이트코드 확인
dis.dis(add)
dis 출력 예시
text
  1           0 RESUME                   0
 
  2           2 LOAD_FAST                0 (a)
              4 LOAD_FAST                1 (b)
              6 BINARY_OP               0 (+)
             10 RETURN_VALUE

특수화 상태 확인

특수화 상태 확인
python
import dis
 
def sum_range(n):
    total = 0
    for i in range(n):
        total += i
    return total
 
# 여러 번 호출하여 특수화 유도
for _ in range(100):
    sum_range(1000)
 
# adaptive=True로 특수화된 바이트코드 확인
dis.dis(sum_range, adaptive=True)

adaptive=True 옵션을 사용하면 특수화된 바이트코드(예: BINARY_OP_ADD_INT, FOR_ITER_RANGE)를 확인할 수 있습니다.

Free-threaded Python과 JIT의 관계

Free-threaded 모드와 JIT는 독립적인 기능이지만, 서로 보완적입니다. 향후에는 두 기능이 결합되어 "GIL 없는 JIT 컴파일 Python"이 가능할 수 있습니다.

두 기능의 조합
text
기본 빌드:           GIL 활성, JIT 없음
Free-threaded:      GIL 없음, JIT 없음
JIT 빌드:           GIL 활성, JIT 활성
Free-threaded + JIT: GIL 없음, JIT 활성 (향후 목표)

현재 두 기능을 동시에 활성화하는 것은 실험적이며, 안정성이 보장되지 않습니다.

실용적 관점의 정리

지금 당장 JIT를 사용해야 하는가

JIT 도입 판단 기준
text
사용을 고려할 경우:
  - Python 성능 연구/실험이 목적인 경우
  - 수치 연산 위주의 내부 도구
  - CPython의 발전 방향을 미리 경험하고 싶은 경우
 
아직 사용하지 않아도 되는 경우:
  - 프로덕션 서비스
  - 성능이 중요하지 않은 스크립트
  - NumPy/pandas 등을 주로 사용하는 경우 (이미 C로 최적화)
Tip

JIT의 현재 성능 향상(2~5%)은 대부분의 실제 애플리케이션에서 체감하기 어려운 수준입니다. 그러나 JIT 인프라가 CPython에 통합된 것 자체가 중요한 이정표입니다. 향후 버전에서 점진적으로 최적화가 추가될 것이므로, JIT의 원리를 이해해두면 미래의 성능 향상을 더 잘 활용할 수 있습니다.

정리

Python 3.13의 JIT 컴파일러는 CPython 성능 향상의 새로운 장을 열었습니다.

  • copy-and-patch 기법으로 빌드 타임에 기계어 스텐실을 준비하고, 런타임에 복사/패치하여 빠르게 기계어를 생성합니다
  • Tier 2 최적화 파이프라인과 연계하여 핫 코드를 자동으로 감지하고 최적화합니다
  • 현재 성능 향상은 2~5%로 제한적이지만, 향후 인라인화, 탈출 분석 등의 최적화가 추가될 기반입니다
  • 소스 빌드가 필요하며, LLVM이 빌드 타임 의존성입니다
  • 실험적 기능으로 프로덕션 사용은 아직 권장되지 않습니다

다음 장 미리보기

9장에서는 Python 도구 생태계의 혁명적 변화인 uv를 다룹니다. pip, pip-tools, virtualenv, pyenv를 하나로 통합한 차세대 패키지 매니저의 설치, 설정, 그리고 실전 워크플로우를 살펴봅니다.

이 글이 도움이 되셨나요?

관련 주제 더 보기

#python#typescript#performance#devtools#concurrency

관련 글

프로그래밍

9장: uv - 차세대 Python 패키지 매니저

Rust로 작성된 차세대 Python 패키지 매니저 uv를 다룹니다. 설치, 프로젝트 관리, 가상 환경, Python 버전 관리, 스크립트 실행까지 실전 워크플로우를 안내합니다.

2026년 2월 1일·14분
프로그래밍

7장: Free-threaded Python - GIL 제거의 시작

Python 3.13의 free-threaded 모드를 심층 분석합니다. GIL의 역사와 문제점, PEP 703의 설계, free-threaded 빌드의 설치와 실전 멀티스레드 성능을 다룹니다.

2026년 1월 28일·16분
프로그래밍

10장: Ruff와 ty - 차세대 린터, 포매터, 타입 체커

Astral의 Ruff(린터/포매터)와 ty(타입 체커)를 다룹니다. 기존 도구 대체, 설정 방법, 규칙 커스터마이징, IDE 통합, 프로젝트 도입 전략을 안내합니다.

2026년 2월 3일·14분
이전 글7장: Free-threaded Python - GIL 제거의 시작
다음 글9장: uv - 차세대 Python 패키지 매니저

댓글

목차

약 17분 남음
  • Python에 JIT 컴파일러가 필요한 이유
    • CPython의 실행 모델
  • Copy-and-Patch: JIT의 핵심 기법
    • 전통적 JIT vs Copy-and-Patch
    • 스텐실의 구조
  • Tier 2 최적화 파이프라인
    • 핫 코드 감지
    • 최적화 예시
  • JIT 빌드와 활성화
    • 빌드 요건
    • JIT 활성화 옵션
  • 현재 성능과 한계
    • 벤치마크 결과
    • 왜 아직 효과가 적은가
  • JIT의 미래 가능성
    • 예상되는 향후 최적화
    • PyPy와의 비교
  • dis 모듈로 최적화 확인
    • 특수화 상태 확인
  • Free-threaded Python과 JIT의 관계
  • 실용적 관점의 정리
    • 지금 당장 JIT를 사용해야 하는가
  • 정리
  • 다음 장 미리보기