본문 바로가기
Spring Framework

JIT (Just-In-Time) 컴파일러와 AOT (Ahead-Of-Time) 컴파일러

by xogns93 2024. 10. 24.

JIT (Just-In-Time) 컴파일러AOT (Ahead-Of-Time) 컴파일러는 Java 또는 다른 언어의 코드 실행과 성능 최적화 방법과 관련된 두 가지 컴파일 기술입니다. 이들은 각각 JVM(Java Virtual Machine)과 네이티브 코드 실행 방식에 중요한 역할을 하며, 성능, 메모리 사용, 빌드 시간 등에서 각기 다른 이점을 제공합니다.

1. JIT (Just-In-Time) 컴파일러

JIT 컴파일러는 프로그램 실행 중에 코드를 컴파일하는 기술입니다. JIT는 주로 JVM에서 사용되며, 프로그램이 런타임 시점에 코드의 일부 또는 전체를 네이티브 코드로 컴파일하여 실행 속도를 최적화합니다.

주요 특징

  • 실행 중 컴파일: JIT는 코드가 처음 호출되었을 때는 바이트코드를 해석하며 실행하다가, 반복 호출되거나 성능상 중요한 부분에 대해 JIT 컴파일을 수행하여 네이티브 기계 코드로 변환합니다.
  • 동적 최적화: 코드가 반복해서 실행될수록, JIT는 프로그램의 실행 특성을 분석하여 더 효율적인 네이티브 코드를 생성합니다. 이를 통해 핫스팟(Hotspot, 자주 실행되는 코드 부분)을 최적화할 수 있습니다.
  • 실행 속도 개선: 자주 호출되는 코드에 대해 네이티브 컴파일이 이루어지면, 바이트코드를 해석하는 시간 없이 빠르게 실행할 수 있으므로 성능이 개선됩니다.
  • 메모리와 시간의 트레이드오프: JIT는 런타임에서 컴파일을 수행하기 때문에, 메모리와 CPU 자원을 추가로 사용하게 됩니다. 특히 처음 실행할 때는 해석 과정과 컴파일이 모두 포함되므로 초기 실행 시간이 느릴 수 있습니다.

JIT 컴파일러의 장점

  • 동적 최적화: 애플리케이션의 런타임 특성을 분석하여 최적화하기 때문에 실행 성능이 뛰어납니다.
  • 자주 호출되는 코드 최적화: 자주 실행되는 부분을 "핫스팟"으로 간주하고, 반복 호출 시 더욱 최적화된 네이티브 코드로 변환합니다.

JIT 컴파일러의 단점

  • 런타임 컴파일 오버헤드: 실행 중 컴파일 작업을 수행하므로, 애플리케이션이 처음 실행될 때 지연이 발생할 수 있습니다.
  • 메모리 사용 증가: 런타임에서 컴파일된 네이티브 코드를 메모리에 유지해야 하므로 메모리 사용량이 증가할 수 있습니다.

2. AOT (Ahead-Of-Time) 컴파일러

AOT 컴파일러는 프로그램이 실행되기 전에 코드를 컴파일하여 네이티브 실행 파일로 만드는 기술입니다. AOT 컴파일은 컴파일러가 바이트코드를 네이티브 기계 코드로 변환하여 애플리케이션이 런타임 시점에서 바로 네이티브 코드로 실행될 수 있게 합니다.

주요 특징

  • 사전 컴파일: 코드가 배포 또는 실행되기 전에 네이티브 코드로 컴파일되므로, 런타임에서 컴파일하는 작업이 필요 없습니다.
  • 빠른 시작 시간: AOT 컴파일된 코드는 이미 네이티브 형태로 컴파일되어 있으므로 애플리케이션이 실행될 때 바로 기계어로 실행됩니다. 이는 JVM의 초기 로딩 시간과 컴파일 오버헤드를 제거하여 빠른 시작 시간을 제공합니다.
  • 메모리 사용 최적화: AOT는 런타임 컴파일이 필요 없으므로 메모리 사용량을 최적화할 수 있습니다. 특히 임베디드 시스템이나 리소스가 제한된 환경에서 유리합니다.

AOT 컴파일러의 장점

  • 빠른 애플리케이션 시작: 이미 네이티브 코드로 컴파일되어 있으므로 시작 시간이 매우 빠릅니다.
  • 지속적인 성능 유지: 컴파일된 네이티브 코드로 바로 실행되기 때문에 성능이 일관적입니다. 특히 자주 실행되는 애플리케이션의 경우 유리합니다.
  • 메모리 절약: 런타임 컴파일로 인한 메모리 오버헤드가 없으므로, 전체적인 메모리 사용량이 감소합니다.

AOT 컴파일러의 단점

  • 최적화 부족: 런타임 특성에 따라 최적화할 수 없기 때문에, JIT와 같은 동적 최적화 기능이 없습니다. 따라서 코드가 런타임에 어떤 식으로 실행되는지 알 수 없고, 그에 맞춘 최적화를 할 수 없으므로 일부 최적화 기회를 놓칠 수 있습니다.
  • 빌드 시간 증가: 네이티브 코드를 생성하는 데 시간이 걸리기 때문에, 전체 빌드 시간이 늘어날 수 있습니다.

JIT와 AOT의 비교

특징 JIT 컴파일러 AOT 컴파일러
컴파일 시점 런타임 애플리케이션 배포 전
최적화 런타임 특성 분석을 통해 동적 최적화 정적 최적화 (런타임 특성 반영 어려움)
실행 속도 초기엔 느리지만, 이후 빠르게 실행 빠른 시작 시간, 일관된 성능
메모리 사용량 런타임에 메모리 사용 증가 가능 메모리 효율적 사용
빌드 시간 빠름 네이티브 컴파일로 인해 빌드 시간이 길어짐
적용 사례 일반적인 JVM 기반 애플리케이션 리소스가 제한된 임베디드 시스템, 네이티브 성능 요구 애플리케이션

JIT와 AOT의 적용 사례

  • JIT 컴파일러는 일반적으로 JVM 기반의 Java 애플리케이션에 사용됩니다. 예를 들어, Java, Scala, Kotlin 등의 언어로 개발된 애플리케이션은 JVM이 JIT 컴파일을 통해 동적 최적화를 수행하여 성능을 높입니다.
  • AOT 컴파일러는 네이티브 코드 실행이 필요한 상황이나, 시작 시간이 중요한 애플리케이션에서 주로 사용됩니다. GraalVM에서 제공하는 AOT 기능은 Java 애플리케이션을 네이티브 이미지를 만들어 시작 시간을 매우 빠르게 하는 데 유용합니다. 또한, Android의 ART(Android Runtime)도 AOT 방식을 사용하여 앱 성능을 향상시킵니다.

Java와 Spring에서의 JIT/AOT

  • Java:
    • JVM은 JIT 컴파일을 기본적으로 사용하여 바이트코드를 실행하며, Java의 HotSpot JVM은 핫스팟(자주 실행되는 코드 부분)을 집중적으로 최적화하여 빠른 실행을 제공합니다.
    • Java 9 이후부터는 JITAOT가 모두 지원되며, 이를 통해 개발자는 각 애플리케이션의 특성에 맞춰 JIT 또는 AOT를 선택할 수 있습니다.
  • Spring Boot:
    • Spring Native 프로젝트는 AOT 컴파일을 사용해 Spring 애플리케이션을 네이티브 이미지로 컴파일할 수 있도록 합니다. 이는 GraalVM을 활용하며, 서버리스 환경이나 컨테이너 기반 환경에서 빠른 시작 시간을 가지는 스프링 애플리케이션을 구축하는 데 유용합니다.

요약

  • JIT 컴파일러는 프로그램이 실행되는 동안 코드 일부를 컴파일하며 동적 최적화를 통해 성능을 향상시킵니다. 그러나 처음 실행 시 컴파일로 인해 느려질 수 있습니다.
  • AOT 컴파일러는 코드 실행 전에 네이티브 코드로 컴파일하므로, 빠른 시작 시간을 제공합니다. 하지만 동적 최적화가 어려워 JIT보다 최적화 측면에서 제한적일 수 있습니다.
  • JIT와 AOT의 사용은 각기 다른 요구 사항에 맞추어 선택되며, 애플리케이션의 특성, 실행 환경, 성능 요구에 따라 적합한 방식을 선택해야 합니다.