0. JVM이란 무엇인가
0.1. JVM이란
- Java Virtual Machine
- OS에 종속받지 않고 CPU가 자바를 인식, 실행할 수 있게 해준다
- Java언어를 OS가 인식할 수 있는 기계어로 컴파일 할 필요 없이 JVM이 인식할 수 있는 Java bytecode로 변환한다
0.2 Hotspot 이란
- 오라클 JDK와 Open JDK 의 기본 가상 머신이자 가장 널리 사용되는 자바 가상 머신
- 핫 코드 감지 기능
- 컴파일했을 때 효과를 가장 크게 볼 수 있는 코드 영역을 런타임에 알아내어 JIT 컴파일러에 알려준다
- JIT 컴파일러가 해당 코드를 메서드 단위로 컴파일
- 자주 호출되거나 시간이 많이 드는 메서드가 있다면 JIT 컴파일을 수행해 스택을 치환
1. JVM 동작

- 동작 과정
- 컴파일
- 클래스 로딩
- 메모리 할당
- 바이트 코드 실행
1.1 컴파일
- 자바 소스를 실행하기 위해선 자바 컴파일러 javac를 이용해 컴파일링 필요
- 자바 소스 코드를 바이트 코드 형식으로 만들어진 .class 파일로 수정한다
- 아래 표의 규칙을 따라 .class파일이 만들어진다
- ex. 모든 클래스 파일은 매직 넘버로 시작(이 파일이 클래스 파일임을 나타낸다)

- HelloWorld 클래스를 javac로 컴파일하면?
- javac HelloWorld.java → HelloWorld.class 생성
public class HelloWorld {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
System.out.println("Hello World");
}
}
}

- 생성자가 자동으로 추가 되므로 생성자랑 main 메서드 두 개 생성
- aload_0 : 생성자에서 this 레퍼런스를 스택 상단에 올려놓는다
- invokespecial : 슈퍼 생성자 호출, 객체 생성 등 특정 작업을 담당하는 인스턴스 메서드 실행
- iconst_0 : 정수형 상수 0을 평가 스택에 push
1.2 클래스 로딩
- JVM이 실행 시점에 클래스들을 메모리로 동적으로 불러오고 준비하는 과정
- 클래스 로더
- 컴파일된 바이트 코드를 읽고 클래스를 메모리에 올린다
- 자바 클래스들을 한 번에 메모리에 올리지 않고, 애플리케이션에 의해 필요할 때 동적으로 메모리에 올린다
- Runtime시 동적으로 클래스를 로드하여 클래스를 처음으로 참조할 때 해당 클래스를 로드
- HelloWorld 명령을 내리면
- OS는 가상 머신 프로세스(자바 바이너리) 구동
- 자바 가상 환경 구성 및 스탠 머신 초기화
- 유저가 작성한 HelloWorld 클래스 파일 실행
- 애플리케이션의 진입점인 main() 메서드를 호출하려면, 가상 머신 실행이 시작되기 전에 클래스를 로드 해야한다 -> 클래스로딩
1.2.1 Loading
- 클래스를 읽어오는 과정
- 클래스 로더에 의해 메모리에 로드된 .class파일을 읽고, 분석하여 데이터를 런타임 데이터 영역 저장
- 클래스, 인터페이스, 메서드, 필드 등에 대한 심볼릭 레퍼런스라는 값을 런타임 상수 풀에 복사
1.2.2 Linking
- 참조와 실제 메모리 주소 값을 연결하는 과정
- 3 단계
- Verify : 로드된 .class 파일이 유효한 지 확인하는 과정
- .class 파일이 JVM의 명세대로 구현되지 않은 경우 에러
- Prepare : 클래스나 인터페이스에 필요한 메모리를 할당
- Resolve : Loading단계에서 복사한 심볼릭 레퍼런스(symbolic reference) 값을 다이렉트 레퍼런스(direct reference)라는 메모리 주소 값으로 변경
- (e.g. Book b = new Book(); // 참조변수 b가 Heap에 저장된 Book의 메모리 주소를 참조하도록 연결하는 과정)
1.2.3 Initialization
- java코드에서 선언한 static 변수와 static 메서드를 지정한 값들로 초기화 및 초기화 메서드를 실행시켜 주는 과정
- 앞선 단계에서 참조에 대한 값을 실제 메모리 주소로 변경하였으므로, 지정한 값들로 초기화
1.2.4 클래스 로더
- Bootstrap
- JDK 내부 클래스 로딩 (java.lang.* 등)
- Extension
- 주로 자바의 표준 라이브러리와 확장 라이브러리를 로드
- Application
- Classpath에 있는 모든 클래스 (.class, .jar) 로딩
3. 런타임 데이터 영역
- JVM이 프로그램을 수행하기 위해 OS로부터 할당 받는 메모리 영역

- 공유 영역 : Heap, Method 영역
- 스레드 별로 할당되는 영역 : PC Register, Stack, Native Method Stack
3.1 Heap
- new 키워드로 생성된 객체와 배열이 저장되는 공간
- GC(Garbage Collector)의 대상
- JVM 성능 튜닝 시 가장 중요하게 관리되는 영역
3.2 Method Area
- 클래스 로더가 로드한 클래스, 인터페이스, static 변수, 메서드 메타정보 등 저장
3.3 PC 레지스터
- 현재 스레드가 실행 중인 바이트코드 명령어의 주소를 저장
- JVM 내부에서의 "명령어 포인터" 역할
3.4 JVM 스택
- 스레드별 메서드 호출 정보 저장, 지역 변수 관리
- 메서드가 호출될 때마다 Stack Frame이 생성 및 종료
3.4 Native Method Stack
- C/C++ 같은 네이티브 메서드가 실행될 때 사용
4. JIT
- Just In Time 컴파일
- 프로그램을 실제 실행하는 시점에 기계어로 번역
- 그때 그때 하는 컴파일
- 자바 프로그램은 바이트코드 인터프리터가 가상화한 스택 머신에서 명령어를 실행하며 시작
- CPU를 추상화한 구조라서 다른 플랫폼에서도 클래스 파일을 문제 없이 실행 가능하지만, 프로그램 성능을 최대로 내려면 네이티브 기능을 활용해 CPU 에서 직접 프로그램을 실행해야만 함
- 이를 위해 프로그램 단위(메서드와 루프)를 인터프리티드 바이트코드에서 네이티브 코드로 컴파일 -> JIT
- 인터프리티드 모드로 실행하는 동안 애플리케이션을 모니터링하면서 가장 자주 실행되는 코드를 발견해 JIT를 수행
- 특정 메서드가 한계치를 넘어가면 프로파일러가 특정 코드 섹션을 컴파일, 최적화
- 장점
- 컴파일러가 해석 단계에서 수집한 추적 정보를 근거로 최적화를 결정
- 상황별로 수집한 다양한 정보를 토대로 올바른 방향으로 최적화가 가능