자바 애플리케이션은 어떻게 실행되는걸까?

자바 애플리케이션을 구현하는 입장에서 자바 애플리케이션은 어떻게 실행되는 것일까 궁금하여 파악한 바를 간략하게 정리하고자 한다.

자바 프로그래밍 언어로 소스 코드(.java)를 작성한다

가장 처음에 우리는 프로그래밍 언어인 자바로 소스 코드를 작성하는데, 이렇게 작성한 소스 코드 파일들은 .java라는 확장자가 붙은 파일들이다.

소스 코드를 컴파일하여 바이트 코드(.class)를 생성한다

우리가 작성한 소스 코드를 자바 컴파일러가 자바 가상 머신이 해석 가능한 바이트 코드로 컴파일하는데, 이렇게 컴파일된 바이트 코드 파일들은 .class 확장자가 붙은 파일들이다.

자바 가상 머신(JVM, Java Virtual Machine)으로 자바 애플리케이션 프로세스를 생성한다

자바 가상 머신(이하 JVM)을 통해 자바 애플리케이션을 실행하면 프로세스가 하나 생성되며, 동시에 운영체제로부터 메모리 영역을 할당 받는다.

JVM의 클래스 로더가 프로그램에 의해 호출되는 바이트 코드를 메모리에 적재하고 링크하며 초기화하고, 이 과정에서 운영체제로부터 할당받은 런타임 데이터 영역에 알맞게 데이터가 저장된다. 그리고 실행 엔진이 메모리에 적재된 바이트 코드를 읽고 해석하여 실행하면서 애플리케이션이 수행된다.

클래스 로더

바이트 코드인 클래스 파일을 읽어서 메모리에 적재하고, 링크하고, 초기화하는 역할을 한다. 이러한 클래스로더는 세부적으로 아래와 같이 분류할 수 있다.

  • 부트스트랩 클래스 로더 : 부트스트랩 클래스패스로부터 클래스들을 적재한다. 최상위 클래스 로더.
  • 확장 클래스 로더 : 확장 경로(jre/lib/ext 폴더나 java.ext.dirs 환경변수에 지정된 경로)로부터 클래스들을 적재한다.
  • 애플리케이션 클래스 로더 : 애플리케이션 레벨 클래스패스, 또는 기타 환경변수 경로로부터 클래스들을 적재한다.

런타임 데이터 영역

자바 애플리케이션 프로세스가 운영체제에게 할당받은 런타임 메모리 영역. 아래와 같이 분류할 수 있다.

  • 매서드 영역 : 클래스 레벨 데이터(static 영역 포함)를 저장하는 영역. 프로세스마다 1개씩 존재. 공유 리소스이며 스레드 세이프하지 않다.
  • 힙 영역 : 모든 객체와 배열이 저장되는 영역. 프로세스마다 1개씩 존재. 공유 리소스이며 스레드 세이프하지 않다.
  • 스택 영역 : 각 스레드마다 가지는 영역, 메서드 호출에 대한 스택 프레임과 로컬 변수가 저장된다. 공유 불가능한 리소스이며 스레드 세이프하다.
  • PC 레지스터 : 각 스레드는 별도의 PC 레지스터를 가지며, 명령 실행 시 현재 실행중인 명령 주소를 저장한다.
  • 네이티브 메서드 스택 : 네이티브 메서드 정보를 가지는 곳. 모든 스레드에 대해 별도의 네이티브 메서드 스택이 만들어진다.

실행 엔진

바이트 코드를 읽고 해석하여 실행하는 역할을 한다. 아래는 실행 엔진에 포함된 컴포넌트들이다.

  • 인터프리터 : 바이트 코드를 하나씩 읽고 해석하여 실행하는 역할. 단점으로는 동일한 바이트 코드가 여러 번 호출되더라도 매번 새로운 해석이 발생한다는 것.
  • JIT(Just In Time) 컴파일러 : 인터프리터의 단점을 해소하기 위해 반복되는 코드를 발견하면 해당 바이트 코드를 컴파일하여 네이티브 코드로 변경하고 이를 반복적인 호출에 사용하여 시스템 성능을 향상시킨다.
  • 가비지 컬렉터 : 더 이상 참조하지 않는 객체를 수집하고 힙 영역에서 제거하는 역할. 이런 과정은 JVM이 자동으로 수행한다.