728x90

Warm Up을 알아보기 전에 Warm Up이 필요한 이유에 대해 알아보겠다.

 

 

서버 배포 직후의 Latency 발생

서버 배포 직후 사용자가 요청을 보냈을 때 유독 응답이 느린 문제가 발생한다.

 

이러한 문제가 발생하는 원인은 크게 두 가지가 있는데

바로 클래스 로더의 지연 로딩과 JIT 컴파일러의 동작 방식 때문이다.

 

 

클래스 로더의 지연 로딩

클래스 로더는 클래스 파일을 찾아 메모리에 적재해 실행 가능하게 만들어주는데

이러한 동작을 자바 애플리케이션이 시작될 때 모두 메모리에 적재하는 것이 아니라

각 클래스들이 직접적으로 필요한 시점에 로딩을 하는 지연 로딩 방식을 사용한다.

 

즉, 서버 배포 직후에 사용자가 요청을 보내면 해당 요청을 처리하기 위해 필요한

클래스들은 당연히 아직 메모리에 적재가 되지 않은 상태일테고

이때부터 클래스 로더가  클래스들을 로딩하게 되기 때문에 배포 초기 Latency가 발생한다.

 

 

JVM의 컴파일 방식

JVM은 인터프리팅 방식과 컴파일 방식을 모두 사용하고 기본적으로 인터프리팅 방식을 사용한다.

 

그렇다면 컴파일 방식은 대체 언제 사용할까?

 

컴파일 방식은 모든 소스 코드를 한 번만 컴파일과 최적화를 해두면

이후에는 별도의 과정 없이 기계어로 읽을 수 있기 때문에

매번 코드를 하나하나 컴파일 하는 인터프리팅 방식보다 빠를 수 밖에 없다.

 

하지만 애플리케이션을 실행할 때 모든 class 파일을 컴파일 후에 실행하면

속도는 당연히 빠르겠지만 애플리케이션의 실행 시간이 많이 소요된다.

 

그래서 JIT 컴파일러는 실행 시 모든 코드를 컴파일 하지 않고 실행 중에 동적으로 컴파일을 진행한다.

 

 

JIT 컴파일러

JIT 컴파일러는 비유하자면 즐겨찾기 방식으로 컴파일을 진행하는데

애플리케이션 실행 중에 자주 실행되는 부분인 핫스팟을 컴파일 한다.

 

GC가 age를 기록하는 것과 비슷하게 JIT 컴파일러도 프로파일링이라는 과정을 통해

실행 중인 애플리케이션의 동작을 분석하고 기록하여 이를 토대로 핫스팟을 식별한다.

 

JIT 컴파일러는 이렇게 식별된 핫스팟을 컴파일해 코드 캐시라는 곳에 저장하여

인터프리팅 방식처럼 매번 하나하나 컴파일 할 필요 없이 저장된 것을 꺼내어 사용하기만 하면 된다.

 

 

JIT 컴파일러의 동작 방식

JIT 컴파일러는 Tiered Compliation이라는 여러 단계로 나뉜 컴파일 과정으로 동작하며

인터프리터와 C1, C2 두 개의 컴파일러로 이루어져 있다.

 

먼저, C1과 C2를 간단하게 살펴보겠다.

 

C1

가능한 빠른 실행 속도를 목적으로 하지만 최적화와 컴파일도 가능한 빠르게 하기 위해

제한된 수준으로만 최적화를 진행하는 컴파일러다.

 

특정 메서드가 일정치 이상 호출되면 C1 컴파일러에 의해 최적화 및 컴파일이 이루어 진다.

 

C2

C1 메서드로 최적화 및 컴파일 된 특정 메서드가 일정치 이상 호출되면 C2 컴파일러에 의해

C1보다 높은 수준의 최적화를 거쳐 컴파일이 진행된다.

 

C1과 C2 컴파일러로 컴파일된 코드는 모두 동일하게 코드 캐시에 저장된다.

 

Tiered Compliation

Tiered Compliation 과정은 0 ~ 4 Level로 구분된다.

 

  • Level 0 : Interpreted Code
    • 애플리케이션 실행 초기에는 모든 코드를 인터프리터를 통해 실행한다.
    • 당연히 컴파일 방식보다 성능이 낮다.
  • Level 1 : Simple C1 Compiled Code
    • 복잡도가 낮은 메서드를 대상으로 컴파일한다.
    • C2 컴파일러로 최적화 및 컴파일을 해도 유의미한 성능 향상이 기대되지 않는다.
    • 따라서 프로파일링도 진행하지 않는다.
  • Level 2 : Limited C1 Compiled Code
    • C2 컴파일러의 큐가 가득찬 경우 제한된 수준의 프로파일링과 최적화를 한다.
  • Level 3 : Full C1 Compiled Code
    • 일반적인 상황에서 수행되는 단계이다.
    • 최대 수준의 프로파일링과 최적화를 한다.
  • Level 4 : C2 Compiled Code
    • 장기적 성능 향상을 목적으로 C2 컴파일러가 최적화를 수행한다.
    • 이 단계에서 최적회된 코드는 완전한 최적화가 이루어져 프로파일링을 하지 않는다.

 

 

JVM Warm Up

Latency가 발생하는 두 가지 원인을 확인했으니 어떻게 해결할지는 단순하다.

 

  • 클래스 로더의 지연 로딩이 발생하지 않게 필요한 클래스들을 미리 사용해둔다.
  • C1, C2 컴파일러를 사용하기 위해 메서드를 미리 일정치 이상 호출해둔다.

 

결국 Warm Up은 후라이팬을 사용하기 이전에 예열을 하는 것처럼 JVM을 예열 시키는 방법이라고 볼 수 있다.

 

코드를 모두 실행해서 모든 클래스를 적재하고 메서드들도 예열시키기는 무리가 있기 때문에

자주 사용될 것으로 예상되는 부분들을 위주로 Warm Up을 진행해주면 된다.

 

각 컴파일러의 컴파일 임계치(Compile Threshold)는 C1은 1,500회, C2는 10,000회이다.

'Java > Notion' 카테고리의 다른 글

자바의 버전별 특징  (0) 2024.03.04
Garbage Collection 파헤치기  (0) 2024.03.03
JVM 뜯어보기 (컴파일, 인터프리팅, JIT, GC, 메모리)  (0) 2024.03.02
자바의 컴파일 과정  (0) 2023.10.25
BigInteger  (0) 2023.05.08

+ Recent posts