네트워크 바이트 오더
를 사용함.자바 어셈블리
라고 함.javap -c
로 활용 가능동적 로드
특징이 있다.JVM이라는 프로그램이 운영체제 위에서 실행되면서 할당받는 메모리 영역이다.
PC 레지스터
- Program Counter 레지스터는 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다.
- PC 레지스터는 현재 수행중인 JVM 명령의 주소를 갖는다.
JVM 스택
- JVM 스택은 각 스레드마다 하나씩 존재하며 스레드가 시작될 때 생성된다.
- 스택 프레임(Stack Frame)이라는 구조체를 저장하는 스택으로, JVM은 오직 JVM 스택에 스택 프레임을 추가하고(push) 제거하는(pop) 동작만 수행한다.
- 예외 발생 시 printStackTrace()등의 메서드로 보여주는 Stack Trace의 각 라인은 하나의 스택 프레임을 표현한다.
스택 프레임
- JVM 내에서 메서드가 수행될 때마다 하나의 스택 프레임이 생성되어 해당 스레드의 JVM스택에 추가되고 메서드가 종료되면 스택 프레임이 제거된다.
- 각 스택 프레임은 지역 변수 배열(Local Variable Array), 피연산자 스택(Operand Stack), 현재 실행 중인 메서드가 속한 클래스의 런타임 상수 풀에 대한 레퍼런스를 갖는다.
- 지연 변수 배열, 피연산자 스택의 크기는 컴파일 시에 결정되기 때문에 스택 프레임의 크기도 메서드에 따라 크기가 고정된다.
지역 변수 배열 (Local Variable Array)
- 0부터 시작하는 인덱스를 가진 배열이다.
- 0-은 메서드가 속한 클래스 인스턴스의 this 레퍼런스이고, 1부터는 메서드에 전달된 파라미터들이 저장되며, 메서드 파라미터 이후에는 메서드의 지역 변수들이 저장된다.
피연산자 스택(Operand Stack)
- 메서드의 실제 작업 공간이다.
- 각 메서드는 피연산자 스택과 지역 변수 배열 사이에서 데이터를 교환하고, 다른 메서드 호출 결과를 추가하거나(push) 꺼낸다(pop).
- 피연산자 스택 공간이 얼마나 필요한지는 컴파일할 때 결정할 수 있으므로, 피연산자 스택의 크기도 컴파일 시에 결정된다.
네이티브 메서드 스택
- 자바 외의 언어로 작성된 네이티브 코드를 위한 스택
- JNI(Java Native Interface)를 통해 호출하는 C/C++등의 코드를 수행하기 위한 스택으로, 언어에 맞게 C스택이나 C++스택이 생성된다.
메서드 영역
- 모든 스레드가 공유하는 영역으로 JVM이 시작될 떄 생성된다.
- JVM이 읽어들인 각각의 클래스와 인터페이스에 대한 런타임 상수 풀, 필드와 메서드 정보, static 변수, 메서드의 바이트코드 등을 보관한다.
- 메서드 영역은 JVM 벤더마다 다양한 형태로 구현할 수 있으며, 오라클 핫스팟 JVM(HotSpot JVM)에서는 흔히 Permanent Area 혹은 Permanent Generation(PermGen)이라고 불린다.
- 메서드 영역에 대한 가비지 컬렉션은 JVM 벤더의 선택 사항이다.
런타임 상수 풀
- 클래스 파일 포맷에서 constant_pool 테이블에 해당하는 영역
- 메서드 영역에 포함되는 영역이긴 하지만 JVM 동작에서 가장 핵심적인 역할을 수행하는 곳이기 때문에 JVM 명세에서도 따로 중요하게 기술한다.
- 각 클래스와 인터페이스의 상수뿐만 아니라, 메서드와 필드에 대한 모든 레퍼런스까지 담고 있는 테이블이다.
- 즉, 어떤 메서드나 필드를 참조할 때 JVM은 런타임 상수 풀을 통해 해당 메서드나 필드의 실제 메모리상 주소를 찾아서 참조한다.
힙
- 인스턴스 또는 객체를 저장하는 공간으로 가비지 컬렉션의 대상이다.
- JVM 성능 등의 이슈에서 가장 많이 언급되는 공간이다.
- 힙 구성 방식이나 가비지 컬렉션 방법 등은 JVM 벤더의 재량이다.
실행 엔진이 어떻게 동작하는지는 JVM 명세에 규정되지 않았다.
따라서 JVM 벤더들은 다양한 기법으로 실행 엔진을 향상시키고 다양한 방식의 JIT 컴파일러를 도입하고 있다.
대부분의 JIT 컴파일러는 다음과 같은 형태로 동작한다.
JIT 컴파일러는 바이트코드를 일단 중간 단계의 표현인 IR(Intermediate Representation)로 변환하여 최적화를 수행하고 그 다음 네이티브 코드를 생성한다.
오라클 핫스팟 VM은 핫스팟 컴파일러라고 불리는 JIT 컴파일러를 사용한다.
핫스팟이라 불리는 이유는 내부적으로 프로파일링을 통해 가장 컴파일이 필요한 부분, 즉 '핫스팟'을 찾아낸 다음, 이 핫스팟을 네이티브 코드로 컴파일하기 때문이다.
핫스팟 VM은 한 번 컴파일된 바이트코드라도 해당 메서드가 더이상 자주 불리지 않는다면, 즉 핫스팟이 아니게 된다면 캐시에서 네이티브 코드를 덜어내고 다시 인터프리터 모드로 동작한다.
핫스팟 VM은 서버 VM과 클라이언트 VM으로 나뉘어있고, 각각 다른 JIT 컴파일러를 사용한다.
클라이언트 VM과 서버 VM은 각각 오라클 핫스팟 VM을 실행할 때 입력하는 -client, -server옵션으로 실행된다.
클라이언트 VM과 서버 VM은 동일한 런타임을 사용하지만, 위 그림과 같이 다른 JIT 컴파일러를 사용한다.
서버 VM에서 사용하는 Advanced Dynamic Optimizing Compoiler가 더 복잡하고 다양한 성능 최적화 기법을 사용하고 있다.