JVM이란 무엇인가? 알아보자
자바 프로그램 실행순서는?
public class Main {
public static void main(String[] args){
}
}
클래스를 IntelliJ나 Eclipse로 만들면 생성되는 Main 클래스와 그 안의 mian 메서드를 많이 봤을 것이다.
IDE에서 코드를 작성하고 Run 버튼을 누르면 콘솔창에는 결과가 나왔는데 그 안에는 아래와 같은 과정들이 포함돼있다.
- 소스코드를 자바 컴파일러로 컴파일한다.(.java -> .class)
- JVM에 컴파일된 바이트 코드를 넣는다
- JVM은 바이트코드를 읽어 OS가 실행할 수 있는 네이티브 코드로 변환 및 실행한다.
JVM은 컴파일된 바이트코드를 읽어와 OS에 맞는 특화된 코드로 변환 및 실행하는 프로그램이다.
소스코드로 쓰는 자바 언어는 플랫폼(운영체제+CPU)에 독립적이지만 컴파일된 바이트코드를 특정 운영체제에서 실행을 하기위해 만들어진 JVM은 플랫폼에 종속적이다.
JVM 구조
컴파일된 바이트코드를 어떻게 실행시키나 알아보기 위해 JVM 구조를 알아보자
클래스 로더 시스템
클래스 파일(바이트코드)를 읽고 클래스 정보를 메서드/힙 영역에 올려둠
메모리
실행 프로그램의 정보가 올라가있는 메모리
실행엔진
인터프리터와 컴파일러로 바이트 코드를 네이티브 코드로 변환 및 실행하며 GC로 메모리 관리
클래스 로더 자세히 알아보기
로딩, 링크, 초기화 순으로 진행된다
로딩
클래스 로더가 .class 파일을 읽어 바이너리 데이터로 변환하고 메소드 영역에 저장한다.
이때 메소드 영역에 저장하는 데이터는
- 패키지 경로가 포함된 클래스 이름(FQCN)
- 클래스, 인터페이스, 이넘 분류
- 메소드와 변수
로딩은 Bootstrap > Extention > Application ClassLoader 순으로 진행된다.
Bootstrap ClassLoader
- $JAVA_HOME\lib의 자바 코어 API(Object.class, String.Class..)를 탑재
Extention ClassLoader
- $JAVA_HOME\lib\ext 시스템 프로퍼티를 탑재
Application ClassLoader
- 애플리케이션의 클래스 패스에 저장된 클래스를 읽어온다(작성한 소스코드 및 라이브러리, 프레임워크)
세 단계의 클래스로더를 거쳐도 클래스를 찾지 못하면 ClassNotFound Exception이 발생한다.
로딩이 끝나면 해당 클래스 타입의 Class 인스턴스를 생성해 힙 영역에 저장한다. 리플렉션 포스팅
링크
아래의 과정들이 순서대로 실행된다.
Verify
.class 파일 형식이 유효한지 체크
Prepare
클래스 변수(static 변수)와 기본값에 필요한 메모리 준비
Resolve(Optional)
논리적인 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 변경하면서 힙에 있는 인스턴스를 가리키는 작업 실행
초기화
static 변수의 값을 할당, 클래스 내의 스태틱 블럭 실행
메모리 자세히 알아보기
공유자원
메소드 영역
클래스 수준의 정보(클래스 이름, 부모 클래스 이름, 메소드, 변수) 저장, 힙에 생긴 객체들도 메서드를 사용하게 되면 메서드 영역 메모리에 있는 메서드를 불러감
힙 영역
실제 데이터를 가진 인스턴스, 배열 등이 저장됨. 가득 차면 OutofMemoryError 발생
쓰레드 별 자원
스택 영역
자바 프로그램이 직접적으로 접근할 수 있는 유일한 메모리 영역, 쓰레드마다 런타임 스택을 쌓고, 그 안의 메소드 호출을 스택프레임이라 부르는 블럭으로 쌓음. 쓰레드 종료 시에 런타임 스택도 사라짐. 가득차면 StackOverflowError 발생
PC(Program Counter) 레지스터
쓰레드 내 현재 실행할 스택 프레임의 주소값을 저장
네이티브 메소드 스택
네이티브 메소드 호출할 때 사용하는 별도의 메소드 스택, 네이티브 메소드는 네이티브 메소드 인터페이스로 네이티브 라이브러리에 접근해서 사용
네이티브 메소드란? 네이티브 키워드가 붙어있고 C , C++로 구현된 메소드
실행 엔진 자세히 알아보기
인터프리터
바이트코드를 한줄씩 네이티브 코드로 변환 및 실행
JIT 컴파일러
인터프리터가 반복되는 코드를 발견하면 JIT 컴파일러로 반복되는 코드를 모두 네이티브 코드로 바꿔두고, 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 실행
GC(Grabage Collector)
힙에서 더 이상 참조되지 않는 객체를 모아서 정리
새롭게 배운 것들
- JVM이 플랫폼 독립적인 것이 아닌 소스코드로 사용하는 자바언어가 독립적, JVM은 플랫폼에 종속적
- 클래스로더의 작동원리
- 인터프리터와 JIT 컴파일러의 간단한 작동원리