JIT(Just-In-Time) Compile이란?

1. 개요

Just-In-Time이라는 이름에서 알 수 있듯, 프로그램의 소스 코드를 프로그램 실행 시 즉석에서(런타임에서) 기계어로 컴파일하여 실행시키는 방식을 말합니다. 주로 인터프리터 언어에서 프로그램 실행속도 향상을 꾀하기 위해 사용하는 프로그램 실행 방식입니다.

2. 상세

2-1. 프로그램의 실행 방식

프로그램은 크게 두 가지 방식으로 실행됩니다.

2-1-1. 컴파일 방식

프로그램을 실행시키기 전 소스 코드를 기계어로 컴파일하여 오브젝트 파일로 만들어 둠. 프로그램 실행 시에는 오브젝트 파일의 기계어를 바로 실행.

  • 오브젝트 파일: 소스 코드를 기계어로 컴파일 한 결과가 저장된 파일
  • 예시: C, C++ 등

2-1-2. 인터프리트 방식

프로그램이 시작되면, 소스 코드(혹은 ByteCode)를 진입점(Main 함수 혹은 실행한 파일의 최상단 코드)부터 한 줄씩 해석.

  • 예시: Python 등

2-2. JIT 방식은 무엇인가?

JIT 방식은 컴파일 방식과 인터프리트 방식을 섞어 놓은 방식입니다. 잘 만들어진 JIT 컴파일러를 사용하면 인터프리트 방식으로 실행되는 프로그램의 실행 속도를 컴파일 방식의 언어와 근사한 수준으로 끌어올릴 수 있죠. 여기서 잠깐, 프로그램 실행 시 즉석에서 코드를 기계어로 번역한다면서요? JIT 방식이 인터프리트 방식과 뭐가 다르길래 컴파일 방식 언어와 실행 속도가 근사하다는 거죠?

그 답은 Chaching에 있습니다.

JIT 방식은 번역이 필요한 소스 코드(혹은 바이트 코드)를 진입점에서부터 한 줄씩 기계어로 번역하다가, 빈번히 실행되는 부분을 발견하면 그 부분의 번역 결과 기계어를 어딘가에 저장해 두고 필요할 때마다 꺼내와 사용합니다. 이것을 Caching(캐싱)이라고 합니다.

진입점에서부터 코드를 한 줄씩 기계어로 번역한다는 점에서 인터프리트 언어의 특성을 가지고 있기도 하고, 기계어로 번역된 코드를 어딘가에 저장해 둔다는 점에서 컴파일 언어의 특성을 가지고 있기도 합니다. 그래서 "컴파일 방식과 인터프리트 방식을 섞어 놓았다"고 얘기하는 것입니다.

2-3. Caching은 어떻게 프로그램 실행속도를 개선하나?

예를 들어 봅시다. 아래와 같은 Pseudo-Code가 있다고 가정하겠습니다.

1) def f(a, b):
2)     return a + b
3)    
4) f(1, 2)
5) f(3, 4)
6) f(5, 6)

위 Pseudo-Code를 보통적인 인터프리트 방식으로 실행시킨다면, 4 -> 1 -> 2 -> 5 -> 1 -> 2-> 6 -> 1 -> 2 라인 순으로 코드가 실행될 것입니다. 4라인에서 함수 f()를 이미 한 번 기계어로 번역한 적이 있음에도, 5, 6라인에 의해 함수 f()를 두 번 더 기계어로 번역하게 되는 거죠.

그러나 JIT 방식에서는 다릅니다. 위 Pseudo-Code를 JIT 방식으로 실행시킨다면, 4 -> 1-> 2 -> (Caching) -> 5 -> 6라인 순으로 코드가 실행될 것입니다. 함수 f()는 한 소스 코드 내에서 반복되어 호출되는 부분이기에, Caching을 해 두었다가 함수 f()를 호출하는 코드를 다시 만나면 Caching해둔 기계어를 불러와 실행시키게 됩니다.

이처럼 JIT 방식 프로그램 실행은 Caching을 통해 인터프리트 방식으로 실행되는 언어의 속도를 개선하여 컴파일 방식 프로그램 실행과 근사한 수준의 실행 속도를 낼 수 있게 해줍니다.

2-4. JIT 방식의 단점

그러나 JIT 방식이 항상 프로그램의 실행 속도를 극적으로 개선해주는 것은 아닙니다. 예를 들어 반복되는 코드가 거의 존재하지 않는 프로그램이라면, 캐싱을 할 코드가 거의 없으니 속도 향상 효과가 미미하겠죠.

또는 프로그램의 실행 시간이 짧은 경우, JIT 방식과 인터프리트 방식 프로그램 실행 속도에는 큰 차이가 없을 것입니다.

그리고, Caching 때문에 정적으로 컴파일 된 프로그램보다 실행 시 메모리를 많이 잡아먹는다는 단점도 있습니다.

좋은 웹페이지 즐겨찾기