About Java Compiler

koonlx·2024년 11월 13일

Java

목록 보기
2/2

It is not inherently interpreted, but can just as well be implemented by compiling its instruction set to that of a silicon CPU. It may also be implemented in microcode or directly in silicon.

oracle official doc에서 해당 문구를 발견했다. java는 인터프리터, JIT 컴파일 방식을 주로 사용하며, AOT 컴파일 방식도 지원하는 것을 저번 Spring Boot 코드 분석을 하며 알게되었는데 실리콘 CPU의 명령어 집합 또는 마이크로 코드로 구현하거나 실리콘에 직접 내장할 수 있다는 내용이다.
그래서 호기심이 생겨 정리해보려 한다.

자바의 컴파일 과정과 JVM

자바는 소스 코드가 실제 실행되기까지 두 번의 컴파일을 거치는 구조로, 이 과정은 자바의 플랫폼 독립성과 성능 최적화를 동시에 가능하게 한다. 두 번의 컴파일은 각각 정적 컴파일(AOT, Ahead-Of-Time)과 동적 컴파일(JIT, Just-In-Time)로 이루어지며, 아래와 같은 과정을 거친다.

  1. 자바 소스 코드(.java)는 자바 컴파일러(javac)에 의해 바이트코드(.class 파일) 로 변환된다.
  2. 이 바이트코드는 JVM에 의해 실행되는데, 이때 인터프리터와 JIT 컴파일러가 동적으로 바이트코드를 네이티브 코드로 변환하여 실행한다.

두 번의 컴파일을 거치면서 자바 프로그램은 코드의 플랫폼 독립성을 유지하면서도 실행 시 성능을 최적화할 수 있다.

첫 번째 컴파일: 정적 컴파일로 .class 파일 생성

자바 컴파일러의 역할: 바이트코드 생성

자바 소스 파일(.java)은 자바 컴파일러(javac)에 의해 플랫폼 독립적인 바이트코드로 변환되어 .class 파일이 된다.

이 바이트코드는 하드웨어에 직접 실행되는 것이 아닌, JVM이라는 가상 환경에서 실행될 수 있는 중간 코드이다.
바이트코드는 특정 CPU나 운영체제에 종속되지 않기 때문에, 이진 형태의 명령어(0과 1)로 이루어진 네이티브 코드와 달리 어떤 플랫폼에서도 동일하게 실행될 수 있는 특징을 가진다.
따라서 자바는 한 번 컴파일된 .class 파일을 여러 운영체제에서 실행할 수 있으며, 이를 통해 플랫폼 독립성을 달성한다.

두 번째 컴파일 및 실행: JVM의 인터프리터와 JIT 컴파일

JVM의 역할과 실행 환경

JVM은 자바 바이트코드를 실제 실행할 수 있는 환경을 제공합니다. 여기서 중요한 것은 JVM 자체가 인터프리터와 JIT 컴파일러를 함께 사용하여 프로그램을 최적화한다는 점입니다. 인터프리터와 JIT 컴파일러는 각각의 역할을 담당하며, 특정 상황에 따라 유동적으로 작동합니다.

인터프리터 방식

JVM이 프로그램을 처음 실행할 때는 주로 인터프리터 방식을 사용한다.

인터프리터 방식: 인터프리터는 .class 파일의 바이트코드를 한 줄씩 읽어 해석하고, 해석된 바이트코드를 곧바로 실행한다.

  • 프로그램이 처음 시작할 때 인터프리터 방식은 실행을 빠르게 시작할 수 있게 해준다. 하지만 각 줄을 해석하고 실행하는 과정을 반복해야 하므로, 반복적으로 실행되는 코드의 경우 성능이 낮을 수 있다.

JIT 컴파일 방식

JVM은 프로그램 실행 중에 반복적으로 호출되는 코드 블록을 감지하면, JIT 컴파일러를 사용하여 네이티브 코드로 변환한다.

자주 사용되는 코드 최적화: 반복되는 루프나 자주 호출되는 메서드는 JIT 컴파일러에 의해 네이티브 코드로 변환되며, 이후에는 JVM이 해석 없이 곧바로 CPU에서 실행할 수 있다.
빠른 성능: JIT 컴파일은 JVM 메모리에 네이티브 코드를 저장해, 이후에는 이 코드가 직접 실행되므로 속도가 크게 향상된다.
예를 들어, 반복 루프나 이벤트 핸들러는 JIT 컴파일러가 이를 감지해 네이티브 코드로 변환하여 실행 속도를 최적화할 수 있다.

JVM의 유동적인 이벤트 기반 최적화

JVM은 프로그램의 실행 상황에 따라 최적화 전략을 실시간으로 조정한다. JVM이 프로그램을 실행하면서 메서드 호출이나 이벤트가 발생할 때마다 인터프리터와 JIT 컴파일러를 적절히 사용하여 프로그램을 최적화하는 것이다. 이를 통해 JVM은 유동적으로 성능을 최적화할 수 있다.

인터프리터와 JIT의 조합: 성능과 유연성의 균형

  • 처음 실행: JVM은 인터프리터로 빠르게 프로그램을 시작하고, 새로운 코드 블록이 호출될 때마다 한 줄씩 해석하여 빠르게 실행한다.
  • 반복되는 코드: 코드가 반복되거나 자주 호출되는 이벤트가 발생하면, JVM은 이를 최적화하여 JIT 컴파일러로 네이티브 코드로 변환한다.
  • 동적 환경 최적화: 프로그램의 실행 상황과 이벤트에 따라 JVM이 실시간으로 최적화 작업을 수행하므로, 애플리케이션은 다양한 환경에서 유연한 최적화가 가능하다.

이러한 구조 덕분에 자바 애플리케이션은 초기 실행 시 빠른 속도로 시작하고, 실행 중에는 성능을 극대화하는 최적화 작업을 지속적으로 수행할 수 있다.

자료를 정리하다보니 내용이 너무 많아서 나중에 내용정리해서 올리겠습니다.

profile
Server Developer

0개의 댓글