Skip to content

JIT

  • JIT란 Just In Time의 약자로, 프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법이다.

  • 일반적인 인터프러터 언어(e.g. cpython)는 바이트코드나 소스코드를 최적화 과정이 없이 번역하기 때문에 성능이 낮다.

  • 반면 정적으로 컴파일하는 언어(e.g. c언어)는 실행 전에 무조건 컴파일을 해야하기 때문에 다양한 플랫폼에 맞게 컴파일을 하려면 시간이 오래 걸린다.

  • JIT는 정적 컴파일러 만큼 빠르면서 인터프러터 언어의 빠른 응답속도를 추구하기 위해 사용한다.

    • 바이트코드 컴파일러가 시간이 많이 소요되는 최적화를 미리 해주기 때문에 바이트코드에서 기계어 번역은 훨씬 빠르게 진행될 수 있다. 또한 바이트코드는 이식성이 뛰어나 가상 머신이 설치되어 있으면 빠르게 실행할 수 있다.
  • 플랫폼 별로 가상 머신을 개발하는 과정은 컴파일러를 만드는 것보다 간단한데, 그 이유는

    1. 복잡한 최적화 과정은 바이트코드 컴파일러가 대신 해주므로 고려하지 않아도 된다.
    2. 바이트코드는 빠른 기계어 변환을 목적으로 설계되었기 때문에 일반적인 컴파일러보다 제작 과정이 수월하다.
  • JIT 코드는 일반적인 인터프러터 언어에 비해 훨씬 좋은 성능을 낸다. 심지어 경우에 따라 AOT(Ahead-Of-Time, 정적 컴파일러)보다 좋은 성능을 내기도 한다. 이는 실행 과정에 컴파일을 할 수 있기 때문에 가지는 장점이라고 할 수 있다.

    1. 실제 타입/값을 알고 최적화할 수 있다. 동적 타입 언어(Python, JS, Ruby 등)는 컴파일 시점에 x가 int인지 string인지 객체인지 알 수 없다. 그래서 AOT 컴파일러는 항상 뭐든 대응 가능한 범용 코드를 생성해야 한다 (타입 체크, boxing/unboxing, dynamic dispatch 등 오버헤드 전부 포함)
      • JIT은 실행하면서 ‘아, 이 루프에서 x는 항상 int였네’를 관찰하고, 그 가정 하에 특화된 빠른 코드를 생성한다. (= trace의 guard)
    2. 실행환경에 맞춰 최적화가 가능하다. AOT 바이너리는 배포될 모든 CPU에서 동작해야 하니 보수적인 명령어 세트를 타겟해야 하는데 반해, JIT은 지금 실제로 돌고 있는 CPU의 명령어 세트(AVX512 지원 여부 등)를 보고 그에 맞는 기계어를 생성할 수 있다.
    3. 정적 컴파일러 언어로 Garbage Collection을 지원하게 만들 수 있지만, JIT 시스템을 이용하면 더 쉽게 GC를 사용할 수 있다.

참고