JVM Architecture

zaccoding·2021년 1월 3일
0

JVM

목록 보기
1/1

해당 내용은 Naver D2 Hello에 포스팅 된 JVM Internal자바 최적화를 기반으로 내용을 정리하였습니다.

Table of Contents


JVM Architecture

(출처: https://dzone.com/articles/jvm-architecture-explained)

JVM 특징

  • 스택 기반의 가상 머신: JVM은 스택 기반으로 동작한다.
  • 심볼릭 레퍼런스: Primitive data type을 제외한 모든 타입(클래스, 인터페이스)을 명시적인 메모리 주소 기반의 레퍼런스가 아닌 심볼릭 레퍼런스를 통해 참조한다.
  • GC: 클래스 인스턴스는 사용자 코드에 의해 명시적으로 생성되고 가비지 컬렉션에 의해 자동으로 소멸된다.
  • 기본 자료형을 명확하게 정의하여 플랫폼 독립성 보장: 기본 자료형을 명확히 정의하여 호환성을 유지하고 플랫폼 독립성을 보장한다.

1. Class Loader

1.1 Loading

(출처: https://www.ibm.com/developerworks/java/library/j-dclp1/index.html?S_TACT=105AGX02&S_CMP=EDU)

Class Loader 특징

  • 계층 구조: 클래스 로더끼리 부모-자식 관계를 이루어 계층 구조로 생성된다.
  • 위임 모델: 계층 구조를 바탕으로 로드를 위임하는 구조로 동작한다. 클래스 로드는 상위 클래스 로더부터 클래스를 로드를 시도한다.
  • 가시성 제한: 하위 클래스 로더는 상위 클래스 로더를 찾을 수 있지만, 상위 클래스 로더는 하위 클래스 로더를 찾을 수 없다.
  • 언로드 불가: 클래스를 로드할 수는 있지만, 언로드는 할 수 없다. (현재 클래스 로더를 삭제하고 새로운 클래스 로더를 생성하는 방법을 사용할 수 있다.)

자바 프로세스가 새로 초기화되면 아래와 같이 Bootstrap, Extension, System(Application), User-Defined 순으로 차례 차례 클래스를 로드한다.

  • Bootstrap Class Loader: 자바 가상 머신이 실행될때 가장 먼저 실행되는 클래스 로더로 자바 런타임 코어 클래스를 로드한다. 주요 역할은 다른 클래스로더가 나머지 시스템에
    필요한 클래스를 로드할 수 있게 최소한의 필수 클래스(java.lang.Object, Class, ClassLoader) 만 로드한다. 또한, VM의 일부분으로 구현되기 때문에 자바 코드로 인스턴스화 할 수 없다.
    (자바 8 이전까지는 rt.jar 파일에서 가져오지만, 자바 9 이후부터는 런타임이 모듈화되고 클래스로딩 개념 자체가 많이 달라졌다고 한다.)
  • Extension Class Loader: Bootstrap Class Loader를 부모로 설정하고 jre/lib/ext에 위치한 자바 확장 클래스들이 로딩된다. 다양한 보안 확장 기능등이 여기에서 로드된다.
    (또한 자바8에 탑재된 JavaScript Runtime Nashorn이 로드된다.)
  • System Class Loader(Application Class Loader): 지정된 ClassPath에 위치한 클래스를 로드하며 -cp, -classpath 를 통해 지정이 가능하다.
  • User-Defined Class Loader: 애플리케이션 레벨에서 사용자가 직접 코드 상으로 생성한 클래스 로더이다.

1.2 Linking

  • Verify: 생성된 바이트 코드를 검증(Java Language Specification 및 JVM Specification)하고 올바르지 않으면 verification error 발생
    (클래스 로드의 전 과정 중에서 가장 까다로운 검사를 수행하는 과정으로서 가장 복잡하고 시간이 많이 걸린다.)
  • Prepare: 클래스가 필요로 하는 메모리를 기본값으로 할당하고 클래스에서 정의된 필드, 메소드, 인터페이스들을 나타내는 데이터 구조를 준비한다.
  • Resolving: 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다.

1.3 Initialization

  • 클래스 변수들을 적절한 값으로 초기화한다.(static (block) initializer, static 필드들을 설정된 값으로 초기화)
  • SuperClass 초기화 진행 후 해당 Class의 초기화를 진행한다.

2. Runtime Data Area

(출처: https://d2.naver.com/helloworld/1230)

Method Area

모든 클래스 레벨의 데이터(런타임 상수 풀, 필드, 메소드 데이터 등)가 저장되는 공간이며, 모든 JVM 스레드들이 해당 영역을 공유한다.

Heap Area

모든 클래스 인스턴스 및 배열 등이 저장되는 공간이며 JVM 당 하나가 존재한다. Thread Safe하지 않으며 가비지 컬렉션의 대상이다.

Runtime Constant Pool

클래스 파일 포맷에서 constant pool 테이블에 해당하는 영역이며 코드 곳곳에 등장하는 상숫값(클래스명, 인터페이스명, 필드명 등)이 존재한다.
JVM은 코드를 실행할 때 런타임에 배치된 메모리 대신 이 상수 풀 테이블을 찾아보고 필요한 값을 참조한다.

JVM Stack Area

각 스레드별로 분리된 Runtime Stack이 생성된다. 모든 메소드 호출마다 Stack Frame이라 불리는 엔트리가 생성된다. 각각의 Stack Frame은 아래와 같은
Local Variables, Operand Stack을 가지며 현재 실행중인 메소드가 속한 클래스의 런타임 상수 풀에 대한 레퍼런스를 갖는다.

  • Local Variable Array: 메소드의 지역변수들을 나타내며, 0번째 변수는 해당 메소드가 속한 클래스 인스턴스의 this 참조값이다.
  • Operand Stack: 메소드 내의 계산을 위한 작업 공간이다.

PC Registers

Program Counter라고도 불리는 PC Register는 각 Thread 마다 하나씩 존재한다(스레드 생성될 때 같이 생성). Native Pointer와 Return Address를 가지고 있으며
Method를 수행할 때 현재 수행되고 있는 Instruction 주소(Native Pointer or Method Bytecode의 시작 offset)를 포함하고 있다.

Native Method Stacks

Native method 정보를 유지하며 각 Thread 마다 별도의 Native Method Stack이 생성된다.


3. Execution Engine

Class Loader를 통해 JVM의 Runtime Data Area에 배치된 바이트코드는 Execution Engine에서 실행된다.

자바 프로그램은 바이트코드 인터프리터가 가상화한 스택 머신에서 명령어를 실행하며 시작된다.

Interpreter

바이트코드를 명령어 단위로 읽어서 실행한다. 한줄씩 수행하기 때문에 느리다(하나의 메소드를 수행할 때 마다 매번 Interpretation을 요구한다).

JIT(Just-In-Time)

Interpreter 방식의 단점을 보완하기 위해 도입된 JIT 컴파일러다. 인터프리티드 모드로 실행하는 동안 애플리케이션을 모니터링하면서 가장 자주 실행되는

코드 파트를 발견해 JIT 컴파일을 수행한다. 특정 메소드가 어느 한계치(threshold)를 넘어가면 Profiler가 특정 코드 섹션을 컴파일/최적화한다.

Garbage Collector

참조되지 않는 객체를 수집하고 제거한다.
(GC에 대한 내용은 다음 포스팅에서 작성)


Links

profile
초보 서버 개발자 :)

0개의 댓글