8장 - 바이트코드 실행 엔진

8.1 들어가며

실행 엔진은 자바 가상 머신의 핵심 구성 요소다. '가상 머신'은 '물리 머신' 에 대한 상대적인 개념으로, 두 머신 모두 코드를 실행하는 기능을 한다. 단, 물리 머신의 실행 엔진은 프로세서, 캐시, 명령어 집합, 운영 체제 수준에서 직접 구현되는 반면, 가상 머신의 실행 엔진은 순수하게 소프트웨어로만 구현된다. 따라서 명령어 집합의 구조와 실행 엔진을 물리적 제약 없이 원하는 대로 만들 수 있다. 하드웨어에서 직접 지원하지 않는 명령어 집합도 실행할 수 있다는 뜻이다.

"자바 가상 머신 명세" 는 바이트코드 실행 엔진의 개념 모델을 정의하고 있고, 이 모델이 주요 업체의 자바 가상 머신 실행 엔진들에 통일성을 심어 주는 핵심이다.

8.2 런타임 스택 프레임 구조

자바 가상 머신은 메서드를 가장 기본적인 실행 단위로 사용하며, 메서드 호출과 실행을 뒷받침하는 내무 데이터 구조로 스택 프레임을 사용한다. 스택 프레임에는 메서드의 지역 변수 테이블, 피연산자 스택, 동적 링크, 반환 주소 같은 정보가 담긴다.

스택 프레임에 할당해야 하는 메모리 크기는 프로그램 실행 중에는 영향을 받지 않고, 오로지 프로그램 소스 코드와 특정 가상 머신 구현의 스택 메모리 레이아웃에 달려 있다.

스레드의 메서드 호출 체인은 매우 길 수 있다. 자바 프로그램 관점에서는 특정 시점에 한 스레드의 호출 스택에 쌓여 있는 메서드듣 모두 현재 실행 중이 상태다. 하지만 실행 엔진 관점에서는 활성 스레드에서 스택 맨 위에 있는 메서드만 실행 중이며, 스택 맨 위에 있는 스택 프레임만 유효하다.

8.3 메서드 호출

메서드 호출은 메서드 본문 코드를 실행하는 일과 다르다. 메서드 호출 단계에서 수행하는 유일한 일은 호출할 메서드의 버전을 선택하는 것이다. 즉, 메서드 본문은 아직 관심 밖이다.

  • 메서드의 버전 : 어떤 상속 관계의 있는 클래스가 있다면 어떤 클래스의 메서드를 실행할 지 결정하는 것을 의미

프로그램을 실행하다 보면 메서드 호출은 매우 빈번하게 일어난다. 하지만 네이티브 코드와 달리 컴파일 과정에서 링킹 단계가 존재하지 않는다. 그래서 클래스 파일에 저장된 모든 메서드 호출은 심벌 참조일 뿐, 직접 참조가 아니다.

그래서 자바는 동적 확장 측면에서 여타 언어보다 뛰어나지만, 메서드 호출 과정이 상대적으로 복잡해졌다. 때에 따라 클래스 로딩 시점에 또는 심지어 런타임에 대상 메서드의 직접 참조를 알아내야 한다.

8.3.1 해석

어떤 메서드는 호출할 버전을 프로그램이 실행되기 전에 알아낼 수 있으면 런타임에는 다른 버전으로 변경될 수 없다. 즉, 컴파일러가 프로그램 코드를 컴파일하는 시점에 호출 대상이 정해진다. 이처럼 호출 대상이 미리 특정되는 경우를 정적 해석이라 한다.

자바 언어에서 "컴파일타임에 알 수 있고 런타임에는 변경될 수 없다" 라는 조건에 부합하는 메서드는 주로 정적 메서드와 private 메서드이다. 따라서 두 유형의 메서드 모두 상속 등을 통해 다른 버전을 만들 수 없으므로 클래스 로딩 단계에서 해석하기 적합하다.

  • 정적 메서드 : 특정 클래스에 고정

  • private 메서드 : 인스턴스 바깥에서 접근할 수 없다.

호출할 메서드 해석은 컴파일타임에 완전히 정해지는 정적인 작업이다. 따라서 런타임까지 기다릴 필요 없이 클래스 로딩의 해석 단계에서 관련한 심벌 참조 모두 명시적인 직접 참조로 변환한다.

반대의 메서드 호출의 형식인 디스패치도 있다.

...

Last updated