PostIT

[Java/JVM] JVM 이해를 통한 Java 작동원리 이해하기 본문

Java

[Java/JVM] JVM 이해를 통한 Java 작동원리 이해하기

shun10114 2017. 6. 1. 10:31

[Java/JVM] JVM 이해를 통한 Java의 작동원리 이해하기



최근 작성일 : 2017.06.01



## 1. JVM이란?


JVM은 물리적 머신을 소프트웨어 구현한 Java 프로그램을 실행할 수 있게 해주는 추상컴퓨팅 시스템입니다. Java는 WORA(Write Once Run Anywhere)의 철학을 위해 VM을 개발하였습니다. JVM은 OS에 상관없이 어느 환경에서도 Java가 실행이 가능토록 만들어 준 것입니다. Java를 컴파일 언어로서 실행하기 위해서는 컴파일을 거쳐야 합니다. Java 컴파일러는 .java 파일을 .class 파일로 컴파일 합니다. 이는 .java 파일을 Java byte code로 변환하여 .class 만드는 것입니다. Byte Code는 기계어가 아니기 때문에 OS에서 바로 실행이 되지 않습니다. 이를 해결하기 위해 JVM을 통해 .class 파일을 로드/해석하여 Java 프로그램을 실행합니다. 

(초기 Java는 JVM의 해석을 거치기 때문에 c언어 같은 네이티브 언어에비해 속도가 많이 느렸습니다. 하지만, JIT(Just In Time)컴파일러를 구현해 이점을 극복했습니다.




[JVM 아키텍쳐 사진]







## 2. JVM은 어떻게 작동되는가?


### 1. Class Loader Subsystem

  • Java의 동적 클래스 로딩 기능은 클래스 로더 하위 시스템에서 처리합니다. 이 시스템은 컴파일 타임이 아닌 런타임에 클래스를 처음 참조 할 때 클래스 파일을 로드/링크/초기화합니다.

1.1 Loading

클래스들은 이 구성 요소에 의해 로드됩니다. Boot Strap class Loader, Extension class Loader 그리고, Application class Loader는 이를 달성하는 데 도움이되는 세 가지 클래스 로더입니다.

Boot Strap ClassLoader

rt.jar 이외의 부트 스트랩 클래스 경로에서 클래스를로드하는 역할을합니다. 이 로더는 우선 순위가 가장 높습니다.


Extension ClassLoader

ext 폴더 (jre \ lib)에 있는 클래스를 로드하는 작업을 담당합니다.


Application ClassLoader

응용 프로그램 수준 클래스 경로, 환경 변수 등을로드하는 데 사용됩니다. 위 클래스 로더는 클래스 파일을 로드하는 동안 위임 계층구조 알고리즘을 따릅니다.


1.2 Linking

Verify

바이트 코드 검증기는 생성 된 바이트 코드가 올바른지 여부를 검증합니다. 검증이 실패하면 검증 오류가 발생합니다.


Prepare

모든 정적 변수에 대해 메모리가 할당되고 기본값이 지정됩니다.


Resolve

모든 기호 메모리 참조가 메소드 영역의 원래 참조로 바뀝니다.


1.3 initialization

이것은 클래스 로딩의 마지막 단계입니다. 여기서 모든 정적 변수는 원래 값으로 지정되고 정적 블록이 실행됩니다.




### 2. Runtime Data Area
  • 런타임 데이터 영역은 5 개의 주요 구성 요소로 나뉩니다.
2.1 Method Area
모든 클래스 수준의 데이터가 정적 변수를 포함하여 여기에 저장됩니다. JVM 당 단 하나의 메소드 영역이 있으며 이는 공유 자원입니다.

2.2 Heap Area
모든 객체와 해당 인스턴스 변수 및 배열이 여기에 저장됩니다. JVM 당 하나의 힙 영역도 있습니다. 메서드와 힙 영역은 여러 스레드에 대한 메모리를 공유하므로 저장된 데이터는 스레드로부터 안전하지 않습니다.

2.3 Stack Area
모든 스레드에 대해 별도의 런타임 스택이 만들어집니다. 모든 메서드 호출에 대해 하나의 항목이 스택 프레임이라고하는 스택 메모리에 만들어집니다. 모든 로컬 변수가 스택 메모리에 생성됩니다. 스택 영역은 공유 리소스가 아니므로 스레드 안전 영역입니다. 스택 프레임은 다음 세 가지 하위 항목으로 나뉩니다.
2.3.1 Local Variable Array
얼마나 많은 지역 변수가 관련되어 있고 해당 값이 여기에 저장 될지와 관련된 메소드입니다.

2.3.2 Operand stack
수행 할 중간 작업이 필요한 경우 피연산자 스택은 작업을 수행하기위한 런타임 작업 공간의 역할을합니다.

2.3.3 Frame data
메서드에 해당하는 모든 심볼이 여기에 저장됩니다. 예외가있는 경우 catch 블록 정보가 프레임 데이터에서 유지 관리됩니다.

2.4 PC Registers
각 스레드는 별도의 PC 레지스터를 가지며, 명령이 실행되면 현재 실행중인 명령의 주소를 유지합니다. PC 레지스터는 다음 명령으로 업데이트됩니다.

2.5 Native Method stacks
네이티브 메소드 스택은 네이티브 메소드 정보를 보유합니다. 모든 스레드에 대해 별도의 원시 메소드 스택이 작성됩니다.



### 3. Execution Engine
  • 런타임 데이터 영역에 할당 된 바이트 코드는 실행 엔진에 의해 실행됩니다. 실행 엔진은 바이트 코드를 읽고 조각 별로 실행합니다.
3.1 Interpreter
인터프리터는 바이트 코드를 더 빠르게 해석하지만 느리게 실행합니다. 해석기의 단점은 하나의 메소드가 여러 번 호출 될 때마다 매번 새로운 해석이 요구된다는 것입니다.

3.2 JIT Compiler
JIT 컴파일러는 인터프리터의 단점을 해소합니다. 실행 엔진은 인터프리터의 도움으로 바이트 코드를 변환하지만, 반복 코드를 발견하면 JIT 컴파일러를 사용하여 전체 바이트 코드를 컴파일하고 원시 코드로 변경합니다. 이 원시 코드는 반복적 인 메소드 호출에 직접 사용되어 시스템 성능을 향상시킵니다.
3.2.1 Intermediate Code generator
중간 코드 생성

3.2.2 Code Optimizer
위에 생성 된 중간 코드를 최적화하는 책임이 있습니다.

3.2.3 Target Code Generator
기계 코드 또는 원시 코드 생성에 대한 책임

3.2.4 Profiler
핫스팟을 찾는 책임이있는 특수 구성 요소, 즉 메소드가 여러 번 호출되는지 여부.

3.3 Garbage Collector
참조되지 않은 오브젝트를 수집하고 제거합니다. "System.gc ()"를 호출하여 가비지 수집을 트리거 할 수 있지만 실행이 보장되지는 않습니다. JVM의 가비지 콜렉션은 작성된 오브젝트를 수집합니다.


3.4. Java Native Interface (JNI)
  • JNI는 Native Method Libraries와 상호 작용하고 Execution Engine에 필요한 Native Libraries를 제공합니다.

3.5. Native Method Libraries
  • 실행 엔진에 필요한 원시 라이브러리의 모음입니다.


## 참조

https://dzone.com/articles/jvm-architecture-explained : JVM Architecture
https://medium.com/@lazysoul/jvm-%EC%9D%B4%EB%9E%80-c142b01571f2 : JVM


Comments