Java

[JVM 밑바닥까지 파헤치기] 8-1. 바이트코드 실행 엔진: 런타임

noahkim_ 2024. 12. 24. 01:56

저우즈밍 님의 "JVM 밑바닥까지 파헤치기" 책을 정리한 포스팅 입니다

 

  • 가상머신의 실행 엔진은 순수하게 소프트웨어로만 구현됨
  • 명령어 집합의 구조와 실행 엔진을 물리적 제약 없이 원하는 대로 만들 수 있음

 

1. 스택 프레임

구성 요소 설명
메서드
- 자바 실행의 기본 단위
- 메서드 호출마다 스택 프레임 생성
스택 프레임 - JVM 스택에 생성되는 메서드 실행용 데이터 구조
- 실행 중인 메서드의 프레임이 항상 스택의 최상단

 

스택 프레임 구성 요소

항목 설명
지역 변수 테이블
- 메서드의 매개변수와 지역변수 저장
- 인덱스 기반 접근 (예: 0 = this, 1 = 첫 번째 매개변수)
- 32비트 단위 슬롯 사용 (long, double은 2슬롯)
피연산자 스택
- JVM 명령어 실행 시 사용하는 임시 저장소
- 연산 결과 저장
- 32비트 단위로 구성됨
- 일부 구현에서는 지역 변수와 공유 영역 존재 (성능 최적화 목적)
동적 링크
- 외부 객체/메서드/필드 등의 심벌 참조 정보
- 런타임 상수 풀에 저장된 심벌을 직접 참조로 변환
반환 주소
- 메서드가 종료되면 호출 지점으로 돌아가기 위한 주소 정보
- PC에 의해 저장 및 복원

 

2. 메서드 호출

정적 해석

  • 메서드 호출 시 컴파일 타임에 호출 대상 메서드가 확정됨
항목 설명
대상 메서드
static, final, private, super, constructor
실행 방식
심벌 참조 → 직접 참조로 변경됨 (컴파일 타임에 결정됨)
관련 명령어
invokestatic, invokespecial, invokeinterface, invokedynamic

 

디스패치

  • 어떤 메서드를 실행할지 정하는 과정
구분 정적 디스패치 동적 디스패치
결정 시점 컴파일 타임 런타임
기준 참조 타입 실제 객체 타입
적용 대상 오버로딩 오버라이딩
대표 명령어 invokestatic, invokespecial 등 invokevirtual
다형성 지원 ❌ (정적 결정)
✅ (실제 객체 기반 호출 결정)

 

메서드 테이블

  • 클래스 로딩 시 생성되는 메서드 주소 테이블
항목 설명
역할
런타임에 동적 디스패치를 빠르게 처리하기 위한 자료구조
구성
오버라이딩된 메서드는 서브클래스에서 해당 슬롯을 덮어씀
참조 흐름
객체 → 클래스 → 메서드 테이블 → 실제 메서드 주소

 

3. 동적 타입 언어

  • 타입 검사 과정이 런타임에 수행됨 (변수 타입은 값이 할당될 때 결정됨)
  • 명확성과 간결성이 뛰어남
  • 성능이 떨어짐

 

런타임 다형성

  • 자바와 같은 정적 타입 언어에서도 런타임 다형성 지원함 

 

메서드 오버라이딩
  • 컴파일 타임: 참조 변수로 호출 가능한 메서드 집합 선택
  • 런타임: 실제 객체 타입에 따라 호출할 메서드 결정 (invokevirtual)

 

동적 타이핑

  • 런타임의 실제 타입에 따라 행동이 결정됨

 

java.lang.invoke 패키지
  • 심벌 참조만으로 호출 대상 메서드를 결정
클래스 설명
MethodHandle
특정 메서드에 대한 경량 참조
→ 함수 포인터처럼 동작, 리플렉션보다 빠름
MethodType
메서드의 파라미터 타입 + 반환 타입 정의
CallSite
런타임에서 메서드 호출 지점을 동적으로 결정하기 위한 객체
실제 메서드 핸들을 바인딩

 

invokedynamic
  • JVM에서 동적 메서드 호출을 지원하는 바이트코드 명령어
항목 설명
목적
자바가 아닌 동적 타입 언어(Python, JavaScript 등)도 JVM 위에서 효율적으로 실행 가능하도록 함
기능
호출할 메서드를 컴파일러가 아닌 사용자 코드가 런타임에 결정
구현 기반
java.lang.invoke의 CallSite, MethodHandle을 사용
대표 활용
- 람다 표현식 (Java 8)
- 프록시 객체 생성
- JVM 기반 동적 언어(JRuby, Nashorn 등)