먼저 자바 소스 파일(.java)은 자바 컴파일러를 통해서 운영체제가 읽을 수 있는 바이트 코드(.class)로 변환된다.
이후 클래스 로더가 이 자바 파일(바이트 코드)를 JVM 위에 올려놓고, 자바 인터프리터에 의해 기계어로 변환되어 실행된다.
자바는 동적으로 클래스를 읽어오므로(동적 로드), 프로그램이 실행 중인 런타임(바이트 코드를 실행할 때)에서야 모든 코드가 자바 가상 머신과 연결된다. 이 동적 로드를 담당하는 부분이 JVM의 클래스 로더이다.
즉, 클래스 로더는 런타임 중에 JVM의 메소드 영역에 동적으로 Java 클래스(.class)를 로드하는 역할을 한다.
자바 바이트 코드(.class)를 메소드 영역에 저장한다.
각 자바 바이트 코드(.class)는 JVM에 의해 메소드 영역에 다음 정보들을 저장한다.(로드된 클래스를 비롯한 그의 부모 클래스의 정보, 클래스 파일과 Class, Interface, Enum의 관련 여부, 변수나 메소드 등의 정보)
검증(Verifying) : 읽어 들인 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 검사한다.
준비(Preparing) : 클래스 및 인터페이스에 필요한 static field 메모리를 할당하고, 이를 기본값으로 초기화를 한다. 기본값으로 초기화된 static field 값들은 뒤의 Initialization 과정에서 코드에 작성한 초기값으로 변경이 된다. 이 때문에 JVM 에 탑재된 클래스 파일의 코드를 작동시키지는 않는다.
분석(Resolution) : Symbolic Reference 값을 JVM 의 메모리 구성 요소인 Method Area 의 런타임 환경 풀을 통하여 Direct Reference 라는 메모리 주소 값으로 바꿔준다. 해당 단계의 영향을 받는 JVM Instruction 요소는 new 및 instanceof 가 있다.
JIT 컴파일러가 컴파일하는 조건은 얼마나 자주 코드가 실행됐는가 이다. 일정한 횟수만큼 실행되고 나면 컴파일 임계치에 도달하고 컴파일러는 컴파일하기에 충분한 정보가 쌓였다고 생각한다.
임계치는 메서드가 호출된 횟수, 메서드의 루프를 빠져나오기까지 돈 횟수 이 두 개를 기반으로 한다. 이 두 수의 합계를 확인하고 메서드가 컴파일될 자격이 있는지 여부를 결정한다. 자격이 있다면 메서드는 컴파일되기 위해 큐에서 대기한다. 이후 메서드들은 컴파일 스레드에 의해 컴파일된다.
아주 오랫동안 돌아가는 루프 문의 카운터가 임계치를 넘어가면 해당 루프는 컴파일 대상이 된다. JVM은 루프를 위한 코드의 컴파일이 끝나면 루프가 다시 반복될 때는 코드를 컴파일된 코드로 교체하고 더 빠르게 실행된다. 이 교체 과정을 "스택 상의 교체(on-stack replacement, ORS)"라고 부른다.
훌륭한 글 감사드립니다.