[Java] JVM (Java Virtual Machine, 자바가상머신)

zerokick·2023년 5월 1일
0

Java

목록 보기
4/12
post-thumbnail

JVM (Java Virtual Machine)


JVM이란?

자바 프로그램 실행 환경을 제공하는 소프트웨어로, JRE(Java Runtime Environment) 내 포함되어 있다.

JVM 특징

  1. 컴파일된 자바 바이트 코드(.class)를 운영체제에 맞는 실행파일로 만들어준다.
  2. 운영체제에 종속되어, 어떤 운영체제에서 컴파일된 바이트 코드 파일이라도 해당 운영체제에서 동작 가능한 기계어로 번역하여 실행한다.
    이로인해 Java가 "Write once, run anywhere" 할 수 있다. (Java는 운영체제에 독립적)

자바 프로그램 실행 프로세스

  1. Java 언어로 작성된 파일을 컴파일러에 의해 중간언어인 바이트 코드 파일로 생성한다.
  2. java.exe 명령으로 JVM을 구동하여 해당 운영체제에 맞는 기계어로 번역한다.

JVM 동작 방식

reference : https://dzone.com/articles/jvm-architecture-explained

JVM은 크게 세 가지 메인이 되는 서브 시스템으로 나눌 수 있다.
1. ClassLoader Subsystem
2. Runtime Data Area
3. Execution Engine

1. ClassLoader Subsystem

자바는 동적 클래스 로딩을 지원한다. 즉, 프로그램 실행 시 모든 클래스를 한번에 메모리에 올려놓는 것이 아니라, 해당 클래스가 런타임 환경에서 참조될 때 Loading, Linking, Initialization의 단계를 거쳐 메모리에 할당된다.

1.1 Loading

클래스들은 하나의 클래스로더에 의해 로드되지 않는다. 클래스의 종류와 경로에 따라 결정된다.

  1. BootStrap ClassLoader : 가장 우선순위가 높은 클래스 로더이며, 부트스트랩 클래스 경로의 로딩에 적합하다. (rt.jar)
  2. Extension ClassLoader : ext 폴더 내의 클래스들을 로딩하는데 적합하다. (jre\lib\ext)
  3. Application ClassLoader : 애플리케이션 레벨의 클래스 경로의 로딩에 적합하다.

1.2 Linking

  1. varify : Bytecode verifier는 생성된 바이트 코드가 적절한지 검사한다.
  2. Prepare : 모든 static 변수들의 메모리가 할당되고, default 값이 할당된다.
  3. Resolve : 모든 Symbolic memory reference들이 Method Area에 있는 original references로 대체된다.

1.3 Initialization

클래스 로딩의 마지막 단계로, static 변수들이 original 값으로 할당되고, static block이 실행된다.

2. Runtime Data Area

클래스로더에 의해 로딩된 클래스들은 Runtime Data Area 영역에 할단된다. 크게 다섯 가지의 주된 컴포넌트로 나뉜다.

2.1 Method Area

static 변수를 포함한 모든 클래스 레벨의 데이터들은 이 영역에 적재된다. Method Area는 JVM당 1개만 존재한다. 또한 이는 공유되는 자원이다.

2.2 Heap Area

모든 객체와 연관되어있는 instance 변수, 배열들이 이 영역에 적재된다. Heap Area는 JVM당 1개만 존재한다. Method Area와 Heap Area는 멀티쓰레드를 위해 메모리를 공유하기 때문에 쓰레드에 안전하지 못하다.

2.3 Stack Area

모든 쓰레드를 위해, 분리된 런타임 stack을 생성한다. 메서드를 호출할 때마다 stack memory 안에 Stack Frame이라 불리는 하나의 entity가 만들어진다. 공유되는 자원이 아니기 때문에 쓰레드에 안전하다. Stack Frame은 다음의 3가지 subentity로 나눌 수 있다.

  1. Local Variable Array
  2. Operand stack
  3. Frame data

2.4 PC Resisters

각각의 스레드들은 별도의 PC Resisger를 갖는다. 이는 현재 실행중인 명령의 정보를 저장하고, 다음 명령 시 업데이트 된다.

2.5 Native Method stacks

native method 정보를 담고 있고, 각 쓰레드들은 별도의 Native Method stack을 만든다.

3. Execution Engine

Runtime Data Area에 할당된 바이트 코드는 Execution Engine에 의해서 실행된다. 바이트 코드를 읽어 한줄 한줄 실행한다.

3.1 Interpreter

바이트 코드를 빠르게 해석할 수는 있지만 실행은 느리다. Interpreter의 단점은 하나의 메서드가 여러번 호출되는 경우, 매번 해석을 해야한다는 것이다.

3.2 JIT Complier

Interpreter의 단점을 극복한다. Execution Engine은 Interpreter를 통해 바이트 코드를 변환하다가, 반복되는 코드일 경우 JIT Compiler를 사용한다. JIT Compiler는 전체 바이트 코드를 컴파일하여 native code로 변환한다. 이 native code는 반복되는 메서드 호출에 대한 퍼포먼스를 향상시키기 위해 직접 사용된다. JIT Compiler는 다음의 네 가지 컴포넌트로 나눌 수 있다.

  1. Intermediate Code Generator
  2. Code Optimizer
  3. Targer Gode Generator
  4. Profiler

3.3 Garbage Collector

Heap 영역 내 참조되지 않는 객체를 수집하거나 제거한다. System.gc()를 통해 호출되지만, 항상 보장되진 않는다.

JNI (Java Native Interface)

Native Method Libraries와 상호작용하고, Execution Engine의 요청에 의해 Native Libraries를 제공한다.

Native Method Libraries

Execution Engine에서 필요로 하는 Native Libraries의 모음이다.

profile
Opportunities are never lost. The other fellow takes those you miss.

0개의 댓글