컴파일러와 인터프리터
컴파일러와 인터프리터는 둘 다 High-Level Language를 기계어로 변환하는 역할을 수행한다.
그러나 컴파일러는 소스코드 전체를 실행 전에 기계어로 변환하지만, 인터프리터는 코드를 실행 도중에 변환한다는 차이점이 있다.
컴파일이 완료된 실행 파일은 인터프리터 방식보다 더 빠르게 실행할 수 있다.
문법 오류 같은 예외는 컴파일 에러를 발생시킴으로써 초기에 발견할 수 있기도 하다.
그러나, 코드가 수정될 때마다 소스코드 전체를 다시 컴파일해야 한다는 단점이 있다.
인터프리터 방식은 전체 코드를 다시 컴파일 할 필요가 없기 때문에, 코드 수정이 용이하다.
또한, 시스템 간의 이식성이 뛰어나다.
그러나, 매번 변환 과정을 거치기 때문에 실행 속도가 컴파일 방식에 비해 느리다.
자바 컴파일러와 자바 인터프리터
기존의 JVM 방식은 컴파일 방식과 인터프리터 방식을 둘 다 채택하였다.
- 자바 파일(.java)을 자바 컴파일러(javac)를 통해, 바이트 코드(.class)로 컴파일
- JVM의 실행 엔진 내에 있는 자바 인터프리터를 통해 바이트 코드를 실행
자바는 운영체제에 독립적인 WORA(Write Once, Run Anywhere) 특성을 구현하기 위해, 물리적인 머신과 별개의 가상 머신인 JVM을 기반으로 동작하도록 설계되었다.
운영체제에 상관 없이, JVM만 동작한다면 바이트 코드를 실행할 수 있는 것이다.
이를 위해, 자바 컴파일러가 자바 소스코드를 JVM이 이해할 수 있는 바이트 코드로 컴파일해주는 것이다.
그렇다면 JVM의 실행 엔진으로 왜 인터프리터를 사용했을까?
컴파일러는 프로그램이 작성된 환경에서 매우 효율적으로 실행되도록 컴파일을 수행해준다.
그러나, 이는 프로그램이 작성된 환경에 의존성을 가지게 된다는 trade-off가 존재한다.
하지만, 자바 인터프리터는 바이트 코드를 한 줄씩 읽어 기계어로 번역하고 실행한다.
따라서 운영체제, 하드웨어와 같은 프로그램이 작성된 환경에 종속적이지 않다!
이는 WORA를 구현하고자 하는 자바의 철학과도 맞닿아있다.
JIT 컴파일러
아 자바는 컴파일 방식과 인터프리터 방식을 둘 다 채택하였구나!
오케이 이해 완료, 오늘 포스팅 끝~
이라고 이번 포스트는 끝나지 않는다.
자바가 단순히 컴파일 방식과 인터프리터 방식만을 사용했을까?
만약 그러했다면 속도가 너무너무 느릴 것이다!
소스코드를 싹다 바이트 코드로 컴파일 한 후, 바이트 코드를 한줄한줄 해석하며 실행하는 구조일 것이기 때문이다.
이러한 성능 문제를 해결하고자 JVM은 JIT 컴파일러를 통해 바이트 코드를 부분적으로 컴파일하여 실행한다!
JIT 컴파일러는 Java 1.3 HotSpot VM부터 도입되었다.
JIT 컴파일러는 코드가 실행되는 과정에 실시간으로 바이트 코드를 컴파일하고 캐싱한다. (Just-In-Time)
그렇다면, 바이트 코드의 어떤 부분이 JIT 컴파일러에 의해 컴파일되는 것일까?
JIT 컴파일러는 자주 실행되는 코드를 컴파일한다.
어떤 코드가 컴파일 임계지 만큼의 횟수만큼 실행되면, JIT 컴파일러는 해당 부분을 컴파일해둔다.
컴파일된 부분은 인터프리터가 필요할 때마다 변환하지 않고, 바로 기계어로 사용할 수 있는 것이다!
int count = scanner.nextInt();
for (int i = 0; i < count; i++) {
...
}
음, 자주 사용되는 코드는 컴파일 및 캐싱하여 사용하는 것이구나!
그렇다면, 위와 같이 동적으로 사용 횟수가 정해지는 코드는 어떻게 되는 거지???
앞서 발했다시피, JIT 컴파일러는 코드 실행 도중에 바이트 코드를 컴파일한다.
동적으로 사용 횟수가 정해지는 코드는 파일이 실행되기 전에는 알 수 없다.
이러한 정보는 런타임에 결정된다.
JIT 컴파일러는 런타임에 컴파일을 수행하기 때문에, 동적 최적화도 가능하다!
우와 JIT 컴파일러 이거 짱이네~
무조건 좋은 거네!
꼭 그렇지만은 않다.
JIT 컴파일러는 런타임에 동작하기 때문에 얻는 장점이 많지만, 그로 인한 단점도 존재한다.
- 컴파일을 런타임에 하기 때문에, JIT 컴파일러가 컴파일을 하는 동안에는 응답 시간이 지연될 수 있다.
- 컴파일 된 코드를 메모리에 저장하고 관리하기 때문에, 일반적인 방식보다 더 많은 메모리를 사용할 수 있다.
- 런타임에 코드를 동적으로 컴파일하는 과정에서 보안 취약점이 발생할 수 있다.
참고:
https://hyeinisfree.tistory.com/26
https://breakcoding.tistory.com/410
https://mangkyu.tistory.com/343
'개발' 카테고리의 다른 글
페이지네이션 (Pagination) (0) | 2025.07.06 |
---|---|
AST에 대한 고찰 (1) | 2025.06.28 |
JVM과 자바의 메모리 관리 (2) | 2025.06.19 |
자바 칩 프라푸치노 (0) | 2025.06.16 |
소프트웨어 아키텍처 패턴 (0) | 2025.06.10 |