자바 아키텍처
위 그림을 보면 JDK에서 JRE 부분이 나누어져 있는 것을 확인할 수 있다.
JRE는 Java Runtime Environment를 의미하며 말 그대로 실행만을 위한 환경이다. 이 JRE만 설치하면 자바를 컴파일하는 등의 각종 프로그램은 제외된 상태로 설치가 된다.
JRE에 포함되어 있는 블록들은 자바에서 제공하는 라이브러리들이다.
자바는 아키텍처에 중립적인 바이트 코드(.class)를 생성한다. 따라서 자바의 버전만 동일하다면, 동일한 프로그램은 어떤 플랫폼에서도 실행할 수 있다. JVM이 이 역할을 해준다.
자바는 실행 환경에서 최대한의 성능을 낼 수 있도록 되어있다. 자동화된 GC도 낮은 우선 순위의 스레드로 동작하기 때문에 높은 성능을 낼 수 있다. 또한 빠른 성능을 위해서 네이티브한 언어로 작성한 부분을 자바에서 사용할 수 있도록 되어있다.
자바는 인터프리터 언어이고 스레드를 제공하고, 동적이라는 의미이다.
자바 인터프리터는 자바 바이트 코드를 어떤 장비에서도 수행할 수 있도록 도와준다.
자바는 멀티 스레드 환경을 제공하기 때문에 동시에 여러 작업을 수행할 수 있다.
자바는 실행시에 동적으로 필요한 프로그램들을 링크시킨다.
JIT는 Just-In-Time의 약자이다. 이는 '동적 변환(Dynamic Translation)'을 의미한다. JIT를 만든 이유는 프로그램 실행을 보다 빠르게 하기 위함이다. 명칭은 JIT 컴파일러이지만 실행시에 적용된다.
기본적으로 프로그램 언어의 실행 방식은 두가지이다. 하나는 한 줄씩 읽고 실행하는 인터프리트 방식, 다른 하나는 컴파일하여 실행 파일을 생성하고 그것을 실행하는 정적 컴파일 방식. JIT는 이 둘을 혼합한 방식이다. 변환 작업은 인터프리터에 의해서 지속적으로 수행되지만 필요한 코드의 정보는 메모리에 올려두었다가(캐시에 담아두었다가) 재사용한다.
자바가 컴파일을 통해 .class 파일을 생성하고 이를 실행하기 때문에 자바를 그냥 정적 컴파일 언어라고 생각할 수 있지만, .class 파일은 JVM이 설치되어 있는 어떤 컴퓨터에서든 실행할 수 있게 만든 바이트 코드이고, 이 바이트 코드를 또 한줄 한줄 읽어서 컴퓨터가 이해할 수 있는 형태(기계어)로 변환하는 작업이 필요하다. 이 변환하는 과정을 JIT 컴파일러에서 실행한다.
위 그림처럼, JIT compiler는 런타임에 실행이되고, 자바 바이트코드(.class 파일)을 기계어로 변환하는 일을 한다.
JIT를 사용하면 반복적으로 수행되는 코드는 매우 빠른 성능을 보인다. 하지만 반대로 처음에 시작할 때는 변환 단계를 거쳐야 하므로 성능이 느리다는 단점이 있다.
JDK 1.3부터 HotSpot JVM이 제공된다.
자바에는 HotSpot Client Compiler, HotSpot Server Compiler 두가지 컴파일러가 있다.
HotSpot Client Compiler: 요즘은 대부분의 PC에 여러개의 코어가 있지만, 예전엔 대부분의 PC가 단일 코어였다. CPU 코어가 하나뿐인 사용자들을 위해 만들어진 컴파일러이다. 이 컴파일러는 애플리케이션 시작 시간을 빠르게 하고, 적은 메모리를 점유하도록 한다.
HotSpot Server Compiler: 코어가 많은 장비에서 애플리케이션을 돌리기 위해 만들어진 컴파일러이다. 이 컴파일러는 애플리케이션의 수행 속도에 초점이 맞추어져 있다.
그렇다면 핫스팟 서버 컴파일러, 핫스팟 클라이언트 컴파일러는 어떻게 선택을 할 수 있는걸까? 기본적으로는 자바가 시작할 때 알아서 클라이언트 장비인지 서버 장비인지 확인한다. 기준은 다음과 같다.
이 두 조건을 만족하면 Oracle에서 만든 JVM은 서버 컴파일러를 선택한다. 만약 명시적으로 어떤 종류의 JVM인지를 지정해주고 싶다면 'java' 명령어로 .class 파일을 실행할 때 '-server', '-client' 등의 옵션을 주면 된다.
$ java -server Calculator
$ java -server -Xms512m Calculator
-Xms 옵션은 JVM의 시작 메모리 크기를 지정해주는 옵션이다. -Xms512m는 512MB의 메모리 크기로 시작하라는 의미이다.
또한, OS에 따라서 서버 컴파일러를 쓸지, 클라이언트 컴파일러를 쓸지가 결정되기도 하는데, 윈도우는 기본적으로 지정해주지 않는다면 클라이언트 컴파일러가 사용된다.