자바 가상 머신 (JVM)
자바로 개발한 프로그램을 컴파일하여 만들어지는 바이트코드를 실행시키기 위한 가상머신 JRE에 포함되어 있으며, JVM이 실행 가능한 환경이면 어디서나 자바 프로그램이 실행될 수 있다. 단, 특정 운영체제의 특수한 기능을 호출하거나 하드웨어를 제어하려면 JNI같은 native 코드를 호출하기 위한 인터페이스를 거쳐야 한다.
JVM 구성
- 클래스 로더 (class loader)
- 로딩, 링크, 초기화
- 실행 엔진 (execution engine)
- 인터프리터, JIT 컴파일러, GC
- 런타임 데이터 영역 (runtime data area)
- 스택, PC, 네이티브 메소드 스택, 힙, 메소드
인터프리터 vs JIT 컴파일러
런타임 데이터 영역에 올라온 자바 바이트 코드를 실행 엔진이 실행시키는데, 두가지 방식이 있다.
인터프리터 방식은 바이트 코드를 명령어 단위로 읽어서 수행하여 한줄씩 수행하여 느리다.
JIT(just in time) 컴파일러 방식은 인터프리터 방식으로 수행하다가 적절한 시점에 바이트코드 전체를
컴파일하여 네이티브 코드로 변경하고, 이 후에는 더이상 인터프리팅하지 않고 네이티브 코드를 직접 실행한다.
네이티브 코드는 캐시에 보관하기 때문에 한번 컴파일된 코드는 빠르게 수행된다.
물론 처음 컴파일 과정은 인터프리팅이 더 빠르기때메 한번만 실행되는 코드는 인터프리팅이 유리하다.
런타임 데이터 영역
스레드들이 생성되며 각 스레드마다 pc, 스택, 네이티브 메소드 스택이 생성된다.
스레드 이외에는 힙, 메소드 영역이 있는데 메소드 영역은 클래스 정보를 처음 메모리 공간에 올릴 때 초기화 되는
대상을 저장하기 위한 메모리 공간이다.
메소드 영역의 Runtime Constant Pool 은 상수 자료형을 저장하여 참조하게 하는데, 중복 막는 역할을 한다.
힙 영역
객체를 저장하는 런타임 데이터 영역 내 메모리 공간. new 연산자로 생성된 객체와 배열을 저장한다.
물론 class 영역에 올라온 클래스들만 객체로 생성가능하다.
힙은 Perm , Young, old 3부분으로 나눌 수 있다.
#### 1. Permanent Generation 영역 (= Perm 영역. Java 1.7 까지는 )
- 생성된 객체들의 정보의 주소값이 저장된 공간. 클래스 로더에 의해 load되는 class, method 등에 대한 meta정보가 저장되는 영역이고, Reflection 을 사용하여 동적으로 클래스가 로딩되는 경우에 사용된다.
#### 2. Young 영역
- Eden : 객체들이 최초로 생성되는 공간
- Survivor 0, Survivor 1 : Eden 에서 참조되는 객체들이 저장되는 공간
#### 3. Old 영역
- Young 영역에서 일정시간 참조되고 있는, 살아남은 객체들이 저장되는 공간. Eden 영역에 객체가 가득 차면 GC가 발생한다. Eden영역에 있는 값들을 Survivor 1 영역에 복사하고 나머지 영역의 객체를 삭제한다. (Minor GC)
만일 Old 영역까지 메모리가 부족하다면 Major gc가 발생하게 된다.
자바 프로그램 실행 과정
- jvm이 os로부터 메모리를 할당받는다.
- 자바 컴파일러가 java파일을 읽어 class파일로 변환시킨다.
- 클래스로더를 통해 class 파일들을 jvm에 로딩한다.
- 로딩된 class 파일들은 실행 엔진을 통해 해석된다. (JIT 컴파일 방식)
- 해석된 바이트코드는 실행 데이터 영역에 배치되어 실질적인 수행이 이루어진다.
이러한 실행과정 속에서 JVM은 필요에 따라 스레드 동기화 및 gc같은 작업을 수행한다.