dev-sohee 님의 블로그
JVM의 부스터, JIT-Compiler 본문
인터프리터는 바이트 코드를 한줄 한줄 읽으면서 OS가 실행할 수 있도록 기계어로 번역을 하는 방식입니다.
초기 JVM은 인터프리터 방식만 이용하여 한줄 한줄 읽기 때문에 실행속도가 느리다는 단점이 있었지만 JIT 컴파일러 방식을 도입해 속도를 보완했습니다. 오늘은 JIT 컴파일러가 무엇인지, 어떻게 JVM의 속도를 개선했다는 것인지 자세히 알아보겠습니다.
* 인터프리터
* 컴파일러
* JIT-Compiler(Just-In-Time)
# 인터프리터와 컴파일러
컴파일러는 소스코드 전체를 컴퓨터 프로세서가 실행할 수 있도록 바로 기계어로 변환합니다.
인터프리터는 고레벨 언어를 중간 코드(intermediate code)로 변환하고 이를 각 행마다 실행합니다.
파이썬은 인터프리트 언어이고 C, C++는 컴파일 언어입니다.
자바는 컴파일러와 인터프리터를 모두 사용합니다.
컴파일러 장점
1. 컴파일이 완료된 실행 파일은 컴퓨터에서 빠르게 실행할 수 있기 때문에 효율적이다.
2. 컴파일 에러(문법적 에러)를 초기에 발견할 수 있다.
3. 0과 1로 된 기계어로 번역되기 때문에 프로그램의 코드가 유출되지 않는다.
컴파일러 단점
1. 코드를 수정하면 컴파일을 다시 해야 한다.
2. 소스 파일 전체를 컴파일해야 하므로 용량이 크다. 따라서 수정 사항이 빈번할 경우 문제가 발생할 수 있다.
3. 모든 소스 파일을 한꺼번에 번역하기 때문에 컴파일 시간이 비교적 느리다.
4. 목적 파일 생성을 위해 메모리를 사용한다.
5. 특정 시스템에서 만들어진 실행 파일이 다른 시스템에서는 실행되지 않는 경우가 많다.
인터프리터 장점
1. 메모리를 사용하지 않는다.
2. 시스템 간의 이식성이 뛰어나다.
3. 전체 코드를 다시 컴파일할 필요가 없기 때문에 코드 수정에 용이하다.
인터프리터 단점
1. 매번 번역 과정을 거쳐야 하기 때문에 실행 속도가 컴파일러에 비해 느리다.
2. 중간 코드로 해석되기 때문에 프로그램의 코드가 유출될 수 있다.
# JIT-Compiler
Java 코드가 실행되는 과정은 그림과 같습니다. Java 코드를 자바 컴파일러(javac)가 바이트코드로 컴파일하여 클래스 파일(.class)을 생성합니다. 즉, 자바 컴파일러는 자바 소스코드를 JVM을 위한 기계어로 변환합니다. 그리고 JVM의 실행 엔진 내에 있는 자바 인터프리터를 통해 바이트코드를 한 줄씩 읽으면서 기계어로 해석(interpret)하고 실행합니다.
자바 컴파일러(javac)를 사용하는 이유는 Java 소스코드(.java)를 CPU가 인식하지 못하므로 기계어로 컴파일을 해줘야 합니다. 하지만 Java는 JVM이라는 가상 머신을 거쳐서 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로 컴파일되는 게 아니라 JVM이 인식할 수 있는 자바 바이트코드(.class)로 먼저 변환이 되야합니다.
자바 코드를 실행하기 위해서는 바이트코드로 컴파일하는 과정과 바이트코드를 인터프리트하는 과정 두 가지를 모두 거쳐야 하기 때문에 컴파일 과정만 필요한 다른 프로그래밍 언어보다 느립니다. 거기에 더하여 인터프리터는 컴파일러보다 느리기 때문에 성능 문제기 발생할 수밖에 없었습니다.
이러한 문제를 개선하기 위해 나온 것이 바로 JIT 컴파일러입니다. 원래 자바의 JVM에서는 인터프리터 방식만 사용했으나 성능 문제가 발생했고 JIT 컴파일러를 추가해서 성능을 개선시키게 된것입니다.
JIT-Compiler 동작 방식
JIT 컴파일러는 프로그램을 처음부터 끝까지 미리 컴파일하지 않고, 프로그램 실행 중 필요한 부분만을 그때그때 컴파일합니다. 이를 통해 초기 로딩 시간을 단축하고, 런타임 성능을 최적화할 수 있습니다.
- 프로그램이 실행될 때, 바이트코드 형태로 로드됩니다.
- 프로그램이 실행될 때 처음에는 인터프리터가 바이트코드를 한 줄씩 해석하여 실행합니다. 이 단계에서 JIT 컴파일러는 아직 동작하지 않습니다.
- JIT 컴파일러는 프로그램 실행 중 자주 호출되는 메서드나 루프 등의 코드를 감지합니다. 이 때 자주 실행되는 코드를 "핫스팟"이라고 합니다. 이는 프로파일링 정보나 히스토리 데이터를 통해 파악됩니다.
- 핫스팟으로 식별된 코드를 JIT 컴파일러가 기계어로 변환합니다. 이 변환은 프로그램 실행 중에 일어나며, 변환된 코드는 캐시에 저장되어 이후 호출 시 빠르게 실행됩니다.
- JIT 컴파일러는 단순히 코드를 변환하는 것뿐만 아니라, 다양한 최적화 기법을 적용합니다. 예를 들어, 인라인(inlining), 루프 최적화, 동적 타입 분석 등을 통해 성능을 높입니다.
- 최적화된 기계어는 이후 호출될 때 인터프리터 대신 실행됩니다. 이는 프로그램의 실행 속도를 크게 향상시킵니다.
**프로파일링이란?: 어떤 함수가 얼마나 시간이 걸리는지, 메모리를 얼마나 사용하는지 등 프로그램의 성능을 측정하는 것
위와 같이 반복되는 코드들을 컴파일하여 캐싱해둠으로써 인터프리터는 반복되는 코드를 읽지 않고 컴파일된 코드를 바로 사용할 수 있습니다.
**캐싱이란?: 핫스팟을 탐지하고 해당 코드를 네이티브 코드로 컴파일한 후 저장하는 과정
JIT-Compiler 장점
1. 실행 속도 향상: 핫스팟 코드를 기계어로 변환하여 실행 속도를 크게 향상시킵니다.
2. 동적 최적화: 런타임 정보를 바탕으로 최적화할 수 있어, 정적 컴파일러보다 더 효율적인 최적화가 가능합니다.
3. 플랫폼 독립성 유지: 바이트코드를 사용함으로써 플랫폼 독립성을 유지하면서도, 실행 성능을 향상시킬 수 있습니다.
**플랫폼 독립성이란?: 자바 프로그램이 특정 운영 체제나 하드웨어에 의존하지 않고, JVM만 있으면 어디서나 동일하게 실행될 수 있음을 의미
JIT-Compiler 단점
1. 초기 컴파일 오버헤드: JIT 컴파일링은 런타임에 수행되므로, 초기 실행 시 오버헤드가 발생할 수 있습니다.
2. 메모리 사용 증가: 기계어를 저장하기 위한 추가 메모리가 필요합니다.
3. 복잡성 증가: 동적 컴파일과 최적화 작업으로 인해 JVM의 실행 환경이 복잡해집니다.
JIT 컴파일러는 자바 프로그램의 속도를 향상시키고 성능을 최적화하는 장점만 있는 줄 알았는데 메모리 사용 및 복잡성 증가라는 단점도 있는 것으로 보아 역시 아직까지 완벽한 프로그래밍 언어는 존재하지 않는 것 같습니다.
'java' 카테고리의 다른 글
Java 8, Java 11, Java 17 뭐가 달라졌는지 알고 사용하자 (0) | 2024.07.28 |
---|---|
JVM의 청소부, GC(Garbage Collector) (0) | 2024.07.13 |
인터페이스와 추상 클래스, 둘 중 뭘 써야 하는거지? (0) | 2024.07.06 |
자바의 두뇌 : JVM의 모든 것 (0) | 2024.07.06 |
JDK vs JRE (0) | 2024.06.22 |