JIT compiler

2022. 12. 11. 00:23JAVA

CS 스터디를 준비하는데 컴파일 언어의 컴파일 과정이 있어서,
인터프리터 언어와 컴파일 언어에 대해 찾아보았다.
문득 자바는 컴파일 언어 아닌가? 싶어서 검색해보았고..  
JIT compiler와 JVM의 구조까지 한번 학습하는 시간을 갖게 된 것이다..

이번 포스팅에서는
1) 인터프리터 언어와 컴파일 언어의 차이
2) 자바는 어떤 언어일까
3) JIT compiler와 JVM의 구조
를 간략하게 적어보겠다.


1) 인터프리터 언어 vs 컴파일 언어

개발자가 작성한 소스코드를 고급언어라고 한다.
둘의 큰 차이점은 고급언어를 컴파일하는지 여부다.

인터프리터 언어

인터프리터 언어는 우리가 작성한 소스코드를 컴파일 하지 않고 한 줄씩 읽으면서 실행한다.

컴파일 과정이 없으니 여기서 시간을 세이브 할 수 있겠지만 한 줄 한 줄 해석하면서 코드를 실행하므로 컴파일 언어에 비해 실행 속도가 느린 편이다.

하지만 컴파일 과정이 없으니 코드를 수정해도 빌드따위 하지않고도 바로 실행이 가능하다. 서버를 재시작하지 않고도 변경사항이 반영된 상태로 테스트를 진행할 수 있다는 뜻이 되겠다.. 

대표적으로 Ruby, Javascript, Python이 있겠다.

컴파일 언어

컴파일 언어는 우리가 작성한 소스코드를 컴퓨터가 알아먹을 수 있는 1)기계어로 변환한 후에  2)변환된 코드가 실행되는 두 단계를 거치는 언어다.

소스코드를 기계어로 변환하는 컴파일 과정이 있으므로 빌드 과정만 보면 인터프리터 언어보다 시간이 더 소요된다. 하지만 런타임 시에는 이미 기계가 먹기쉬운 언어로 상차림이 돼있으니 빠르게 실행할 수 있다.

대표적으로 C, C++이 해당한다. 

요약
인터프리터 언어는 빌드과정 없이 바로 고급언어를 한 줄 씩 읽어서 실행하며
컴파일러 언어는 .class 파일 등과 같이 기계어로 변환한 뒤 실행한다.


2) 자바는 어떤 언어일까

둘의 차이를 살펴보면서 Java는 어디에 해당하는가 궁금했다.

출처: https://junhyunny.github.io/information/java/jvm-execution-engine/

compile

Java는 여타 컴파일 언어처럼 컴파일러를 통해 한방에 기계어로 변환한다.
JVM이 알아먹을 수 있는 바이트코드로 변환하는 것이다.

Interpreter

Java는 JVM이라는 OS에 독립적인 추상층을 제공한다.
Java가 OS에 독립적으로 실행되기 위해 JVM에서는 자바 인터프리터(Java Interpreter)를 이용해 컴파일 된 .class 파일을 OS 환경에 맞는 2진 코드(010010001)로 변환하는 과정을 거친다. 

 

=> 그래서 Java는 하이브리드 언어라고 한다..
가만보면 Java는 컴파일하는 시간도 필요하고.. 기껏 컴파일했더니 한 줄씩 인터프리터로 실행하니
"Java는 느리다", "똥바"라는 얘기가 나왔던 것 같다.

이를 개선하기 위해 JIT Compiler가 등장했다고 한다.

 


3) JIT compiler와 JVM의 구조

JVM의 구조를 먼저 살펴보자.

1) Class Loader: 컴파일 된 .class 파일들을 Runtime Data Area에 적재하는 역할을 수행한다.
2) Runtime Data Area: JVM의 메모리 구조
3) Execution Engine(실행 엔진): 클래스 파일을 실행시키는 방법에 따라 크게 인터프리터, JIT 컴파일러로 구분된다.

중요한 개념이 많지만 여기서는 실행 엔진의 JIT Compiler를 다룬다.

참고로 JIT 컴파일러는 JVM이 해석할 수 있는 바이트코드로 변환해주는 Compiler와 완전히 다른 개념이다.
아래 테코톡 영상에서는 이 컴파일러를 프론트앤드 컴파일러, JIT 컴파일러를 백엔드 컴파일러라고 부른다. 

https://www.youtube.com/watch?v=UzaGOXKVhwU&t=842s 

아까 초기 JVM의 문제점으로 인터프리터방식만 이용하여 한줄 한줄 읽기 때문에 실행속도가 느리다는 단점이 있었지만 JIT 컴파일러 방식을 도입해 속도를 보완했다고 했다.


JIT(Just In Time) 컴파일이란

프로그램을 실제 실행하는 시점에 기계어로 번역하는 컴파일 기법을 말한다.

이를 통해 속도 보완이 가능한 이유는
실행 시점에 인터프리트 방식으로 바이트 코드를 이진 코드로 변환할 때 해당 코드를 캐싱하여, 같은 함수가 여러 번 불릴 때 매번 변환하는 작업을 방지하기 때문이다. 

쉽게 말하면 자바 인터프리터가 "이놈의 똑같은 메소드 언제까지 계속 이진코드로 반복 변환해야되냐~" 궁시렁거릴때
JIT 컴파일러가 "여기 이진 코드로 이미 캐싱해 뒀음ㅎㅎ" 하고 이쁨받을 수 있는 것이다.
물론 모든 메소드가 캐싱 대상은 아니고 메소드의 호출 횟수 등 내부적으로 설정한 임계치가 있는데 이를 넘어서는 경우 캐싱한다고 한다. 

사용자가 처음 실행할 때 바이트코드를 컴파일해서 기계어 실행파일로 변환해 놓고(캐싱) 이 파일을 대신 실행하는 방식으로 바꾸면서 속도를 대폭 향상시키는 효과를 얻었다고 한다.

보통 JIT 컴파일은 최초 실행할 때 한 번 컴파일해서 기계어 실행파일을 만들어 놓고 그 이후에는 원본의 내용이 바뀌지 않았다면 이전에 컴파일해 두었던 기계어 파일을 실행시키는 방식으로 사용되는 것이다.

이것도 요약하자면 "Java의 JIT Compiler는 인터프리터가 자주 사용하는 코드의 정보를 캐시에 담아두었다가 미리 꺼내서 바로 실행하는 것으로 Java Interpreter를 보조하는 역할을 수행한다." 정도가 되겠다.

 

'JAVA' 카테고리의 다른 글

[Java] Record Class란?  (2) 2023.06.12
스트림(Stream) 소개  (0) 2022.12.25
Java - Calculator 과제 회고  (0) 2022.10.30
Java 숫자야구  (0) 2022.10.21
Collection과 Iterator  (0) 2022.10.20