Java, JVM, JDK, JRE
위 네 가지의 차이점에 대해 알아보자.
JVM (Java Virtual Machine)
- 자바 가상 머신으로 자바 바이트코드 (.class)를 OS에 특화된 코드로 변환하여 실행한다.
- 바이트코드를 실행하는 표준이자 구현체
JRE (Java Runtime Environment)
- 자바 애플리케이션을 실행할 수 있도록 구성된 배포판
- 개발 관련 도구는 포함하지 않는다. (JDK에서 제공하기 때문)
- 개발자는 JRE만 사용하는 경우가 매우 드물다.
JDK (Java Development Kit)
- JRE + 개발 툴
- 개발 툴은 javadoc, jar, javap, apt… 등을 제공한다.
자바
- 프로그래밍 언어
- JDK에 들어있는 자바 컴파일러 (javac)를 사용하여, 바이트코드 (.class 파일)로 컴파일 할 수 있다.
JVM 구조
클래스 로더 시스템
- .class 에서 바이트코드를 읽고 메모리에 저장
- 로딩 : 클래스 읽어오는 과정
- 링크 : 레퍼런스를 연결하는 과정
- 초기화 : static 값들 초기화 및 변수에 할당
로딩
요청이 들어오면 아래 순서로 진행된다.
- System Class Loader가 Extension Class Loader에게 위임
- Extension Class Loader가 Bootstrap Class Loader에게 위임
- Bootstrap → Extension → System 순으로 클래스를 찾음
- System Class Loader에서 찾지 못하면, 예외 발생!
- Bootstrap Class Loader : Java의 핵심 클래스들을 로드한다. (java.lang 패키지 등과 같은 핵심 Java API)
- Extension Class Loader : Java의 표준 확장 API를 로드한다. (javax 패키지와 같은 표준 확장 API들이 이에 해당)
- System Class Loader : 애플리케이션 클래스 경로에 있는 클래스와 패키지를 로드. 일반적으로 개발자가 작성한 사용자 정의 클래스를 로드한다.
- Application Loader : 일반적으로 이 용어는 개발자가 작성한 사용자 정의 클래스를 로드하는 클래스 로더를 가리키는데 사용된다. 시스템 클래스 로더와 같은 것으로 간주될 수 있지만, 경우에 따라 다른 커스텀 클래스 로더를 사용할 수도 있다.
링킹
Verify
Verification 단계에서는 클래스 파일이 유효한지 확인한다. 예를 들어, 클래스 파일 내부에 사용되는 모든 타입이 올바르게 사용되었는지, 필드와 메서드가 적절한 범위 내에서 참조되는지 등을 검증한다.
이 단계에서 바이트코드의 구문 분석이나 타입 체크 등이 수행된다.
검증이 실패하면, VerifyError 예외가 발생하며, 클래스 로딩이 중단된다.
Prepare
클래스나 인터페이스의 정적 필드에 대한 메모리 공간을 할당하고, 기본값으로 초기화 한다.
이 과정에서 클래스나 인터페이스의 필드와 메서드의 심볼릭 레퍼런스를 만들어 놓는다.
Resolve
클래스나 인터페이스의 이름을 런타임 환경에서 사용할 수 있는 이진 형식의 참조로 변경.
이 단계에서 클래스나 인터페이스를 찾아서 로드하고, 필요한 링크를 수행한다.
-> 심볼릭 메모리 레퍼런스를 메서드 영역에 있는 실제 레퍼런스로 교체한다.
초기화
클래스의 정적 필드를 초기화하고, 정적 블록을 실행한다.
메모리
메서드 영역
- 메서드 영역에는 클래스 수준의 정보 (클래스 이름, 부모 클래스 이름, 메서드, 변수)저장한다.
- 공유 자원이다.
힙 영역
스택 영역
- 쓰레드마다 런타임 스택을 만들고, 그 안에 메서드 호출을, 스택 프레임이라 부르는 블럭으로 쌓는다.
PC Register
- 쓰레드마다 쓰레드 내 현재 실행할 스택 프레임을 가리키는 포인터가 생성된다.
네이티브 메서드 스택
- 네이티브 메서드 스택은 Java 프로그램이 네이티브 메서드를 호출할 때 사용되는 메모리 영역이다.
- 네이티브 메서드란, native 키워드가 붙은 메서드
- Java가 아닌 다른 프로그래밍 언어로 작성된 메서드로 주로 C, C++ 같은 저수준 언어로 작성된다.
- 네이티브 메서드가 구현된 것을 네이티브 메서드 라이브러리라고 한다.
- 네이티브 메서드 라이브러리는 JNI(네이티브 메서드 인터페이스)를 통해 사용해야 한다.
실행 엔진
인터프리터
- 바이트코드를 기계어로 변환하고, 해당 기계어를 실행하는데 관여한다.
JIT 컴파일러
- 인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면, JIT 컴파일러로, 반복되는 코드를 모두 네이티브 코드로 바꿔둔다. 그 다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용한다.
GC
- 더 이상 참조되지 않는 객체를 모아서 정리한다.
추후에 공부 후 따로 올릴 예정
JNI
- 자바 애플리케이션에서 C, C++, 어셈블리로 작성된 함수를 사용할 수 있는 방법 제공
- Native 키워드를 통한 메서드 호출
- Threa, CurrentThread 메서드 등은, 자바가 아닌 C로 구현되었다.