JIT 컴파일러는 두가지 형태로 나뉩니다. 사용할 형태는 흔히 애플리케이션이 실행되고 있을때 해야할 컴파일러 튜닝에 따라 결정됩니다.
두개의 컴파일러는 클라이언트와 서버로 알려져 있습니다.
JVM 개발자 들은 흔히 c1(컴파일러 1, 클라이언트 컴파일러) 와 c2(컴파일러 2, 서버 컴파일러) 라는 이름으로 부릅니다.
두 컴파일러의 주요 차이점은 코드 컴파일에 있어서의 적극성 유무입니다.
클라이언트 컴파일러
서버 컴파일러보다 먼저 컴파일을 하기 시작합니다. 이는 서버 컴파일러보다 상대적으로 많은 코드를 컴파일한다는 의미이며 코드가 실행되기 시작하는 시간동안 클라이언트 컴파일러가 보다 더 빠를것입니다.
서버 컴파일러
클라이어트 컴파일러보다 더 많은 정보를 바탕으로 컴파일을 하고 더 나은 최적화를 제공합니다. 결국 애플리케이션이 장기간 작동을 한다면 서버 컴파일러가 클라이언트 컴파일러보다 더 빠를것입니다.
각각의 컴파일러에 대한 트레이드 오프는 프로그램이 수행되는 기간과 초기 스타트업 시간의 중요도를 바탕으로 선택합니다.
만약 JVM이 시작할 땐 클라이언트 컴파일러로 작동하다가 코드가 많이 호출되면 서버 컴파일러로 바꿀 수 없을까?
하는 생각에서 시작된 기법이 티어드 컴파일(tiered compilation)이라고 합니다.
티어드 컴파일을 이용하면 코드는 먼저 클라이언트 컴파일러로 컴파일 되고 많이 쓰이게 되면 역최적화 후 서버 컴파일러로 재컴파일 된다. 재 컴파일 되는 시간은 성능에 영향을 줄 정도로 크지 않다.
티어드 컴파일은 자바 8 부터 기본으로 사용할 수 있습니다.
빠른 스타트업이 주 목적일때 클라이언트 컴파일러가 가장 자주 사용됩니다.
단순한 HelloWorld 어플리케이션은 컴파일러가 어떤 기여도 할 수 없기 때문에 유리한 컴파일러가 없습니다.
NetBeans은 중간 크기의 자바 GUI 애플리케이션입니다. 스타트업할 때 약 10,000개의 클래스를 로드하고 몇개의 그래픽 객체를 초기화시키는 등의 작업을 합니다.
여기서 클라이언트 컴파일러는 스타트업할 때 매우 유리합니다. 서버 컴파일러는 38.5% 늦게 시작하며 1초 가량으로 뚜렷한 차이를 보입니다.
여기서 티어드 컴파일러도 클라이언트 컴파일러보다 약 8% 느리다는 점에 주목하면 됩니다.
GUI 프로그램 같은 경우는 더 빨리 시작할 수록 사용자에게 더 성능이 좋다고 느껴지는 프로그램입니다.
만약 전반적인 성능이 확실히 더 중요하다고 느껴지는 경우가 아니라면 클라이언트 컴파일러를 사용하는게 맞습니다.
고정된 양의 작업을 수행하는 배치 어플리케이션에서 컴파일러의 선택은 중요한 요소입니다.
1~ 100000개의 주식에 대해 1년치 이력을 요청하는 애플리케이션이 있다고 할때
입니다.
1~100 개의 작업을 할 땐 클라이언트 컴파일러가 더 빨리 작업을 완료 했습니다. 그 후 성능상의 이점은 서버 컴파일러와 티어드 컴파일러 쪽으로 기웁니다.
티어드 컴파일이 항상 표준 서버 컴파일러보다 약간 더 성능상에 우위가 있다는 점도 흥미롭습니다.
이론상으로 일단 프로그램의 핫스팟을 전부 컴파일하기 충분할 정도로 스타트업 됐다면 서버 컴파일러의 성능이 더 나을 것으로 예상할 수 있습니다.
하지만 애플리케이션은 거의 항상 드물게 실행되는 작은 영역의 코드를 가지고 있고 티어드 컴파일러는 이 부분을 컴파일 했겠지만 서버 컴파일러는 인터프리트 모드로 실행했을 것입니다.
장기수행 어플리케이션에서 컴파일러의 성능 차이
장기 수행 어플리케이션은 전형적으로 코드의 주요 부분이 전부 컴파일 될 정도로 충분히 오래 실행됐다는 의미입니다.
준비기간이 0초 더라도 충분히 컴파일러는 핫스팟을 컴파일할 기회가 많습니다. 그러므로 이 예제에서는 서버 컴파일러 쪽이 더 낫습니다.
앞의 내용과 같이 티어드 컴파일은 단독 서버 컴파일러보다 코드를 조금 더 많이 컴파일하고 조금 더 나은 성능을 지어짜낼 수 있습니다.