카테고리 없음

[JAVA] JIT 컴파일러가 필요한 이유, 자바 인터프리터와 차이점

Hannana. 2024. 7. 29. 23:55
728x90
반응형

바이트코드는 JVM의 실행 엔진에 의해 실행된다.

공부를 하다보니, 인터프리터와 JIT컴파일러는 둘 다 JRE안에 속해있고

바이트 코드를 기계어로 해석하는 점이 비슷해보였다.

그럼 둘의 차이가 무엇일까?

 

-> 자바 인터프리터는 바이트 코드를 한 줄씩 읽고 실행하는 방식으로 동작한다.

이는 프로그램의 실행이 비교적 느릴 수 있지만, 실행 초기 단계에서는 빠른 시작을 제공한다.

JIT컴파일러가 동작하기 전까지 실제로 인터프리터를 초기에 사용한다. ( 느리지만 빠른 시작)

 

-> JIT (Just-In-Time) 컴파일러는 바이트 코드를 기계어로 동적으로 변환하여 실행 속도를 크게 향상시킨다.

프로그램 실행 중 자주 사용되는 코드 부분(핫스팟)을 미리 컴파일하여 실행 속도를 최적화한다.

JIT 컴파일러는 인터프리터가 처음에 실행되다가 특정 코드 블록이 자주 사용되는 것을 감지하면,

해당 부분을 기계어로 컴파일하여 캐시에 저장한 후, 다음 실행부터는 인터프리터 대신 컴파일된 기계어 코드를 사용한다.

 

1. JIT 컴파일러가 필요한 이유

인터프리터는 정직하게 클래스를 로드하고 기계어로 번역한다.

but... 로드≠ 호출 ⇒ 오버헤드 과하게 발생 (자바 초기 모델)

 

 

 

2. 해결 방안

미리 클래스를 binary code로 변환해놓지 말고, 메인 코드에서 사용될 때 로드하자.

 

이렇게 클래스가 사용되면

코드들이 실시간으로 실행되면서 0,1로 바뀌어 JVM의 코드 캐시 영역에 저장

 

 

3. JIT컴파일러 동작 순서

 

1) 초기 실행: 프로그램이 처음 실행될 때 인터프리터가 바이트코드를 한 줄씩 읽고 실행한다.
이 시점에서 메서드 영역에 클래스 메타데이터와 클래스 변수, 메서드 등이 저장됨

2) 핫스팟 감지: 인터프리터가 실행되는 동안 JVM은 어떤 코드 블록이 자주 실행되는지 모니터링.
자주 실행되는 코드 블록(핫스팟)이 감지되면, 이 코드 블록이 JIT 컴파일러로 전달된다.

3) JIT 컴파일: JIT 컴파일러는 감지된 핫스팟 코드를 네이티브 코드로 컴파일한다.

4) 코드 캐시 저장: 컴파일된 네이티브 코드는 코드 캐시 영역에 저장된다. 이후 이 코드 블록이 다시 실행될 때는 인터프리터가 아닌 코드 캐시에 저장된 네이티브 코드가 실행된다.

 

 

 

4. (변동) 자바 컴파일 순서

  1. MyRoom.class 파일 찾기
    컴파일된 .class 파일 찾기 - 만든 클래스들은 컴파일 되어 .class 형태로 저장되어있기 때문

  2. JVM으로 로딩
    class 파일을 JVM으로 로딩

  3. bytecode 검증
    JVM은 로딩 된 bytecode를 검증한다. bytecode가 유효한지 확인

  4. binary로 재해석
    이 단계는 JIT 컴파일러가 도입되면서 불필요해짐


  5. Method Area에 기억
    검증된 bytecode는 Method Area에 저장된다.
    (클래스 변수-로컬변수와 메서드들과 함께 저장)

  6. main() 호출
    최종적으로 main() 메서드가 호출되면서 프로그램이 실행된다.

 

 

 

 

4. 요약


JIT 컴파일러의 역할은 필요한 부분만 실시간으로 바이트코드를 native binary 코드로 변환하여
JVM 코드 캐시 영역에 저장하고 사용하여 실행 속도를 향상시킨다.
즉, 처음에는 인터프리터가 메서드 영역에 클래스 변수와 함께 바이트코드를 실행하며,

핫스팟 코드가 감지된 후에야 그 코드가 네이티브 코드로 컴파일되어

코드 캐시 영역에 저장하고 필요할 때 꺼내쓰는 것이다.

 

 


위의 경우 Java 클래스 파일 (예: String.class, TV.class, System.class)이 JVM에 의해 로드되고,
필요한 부분이 JIT 컴파일러에 의해 네이티브 코드로 변환되어 실행 성능을 최적화한다.

 

 

 

 

 

 

반응형