본문 바로가기
BackEnd/Java

Java Virtual Machine

by 규난 2023. 10. 14.
728x90

목차

  1. 정의
  2. JVM의 구조와 동작 방식
  3. Class Loader
  4. Execution Engine
  5. Runtime Data Areas
    1. Method Area
    2. Heap
    3. PC Register
    4. JVM Stacks
    5. Native Method Stacks
  6. reference

 

1.  정의

자바 컴파일러로 자바 코드를 컴파일 시켜 얻은 바이트 코드를 해석하고 실행하는 가상 머신입니다.

JVM은 WORA(Write Onece Run Anywhere)를 구현하기 위해 자바 언어와 기계어 사이에 바이트 코드를 사용하기 때문에 OS로부터 독립적으로 프로그램을 제약 없이 실행이 가능합니다.

 

2.  JVM의 구조와 동작 방식

JVM 구조

자바 컴파일러를 통해서 컴파일된 바이트 코드가 JVM의 Runtime Data Areas에 올라가기까지의 과정은 이렇습니다.

  1. 클래스 로더의 동적 로딩을 통해 필요한 바이트 코드를 loading, linking, initialization을 통해 JVM 메모리 영역인 Runtime Data Areas에 올라가게 됩니다.
  2. Runtime Data Areas에 올라간 바이트 코드는 Execution Engine을 통해 기계어로 해석돼 실행되게 됩니다.

 

3.  Class Loader

JVM의 Class Loader는 클래스와 인터페이스를 동적으로 로드, 링크 및 초기화합니다.

Class Loader는 Loading -> Liking -> initiallization 과정을 걸쳐서 클래스를 Runtime Data Areas에 올리게 됩니다.

 

Loading

자바 컴파일러를 통해 컴파일된 바이트 코드를 JVM으로 로딩하는 작업을 합니다.

 

Linking

로딩된 바이트 코드를 초기화하기 전에 검증하는 작업을 합니다.

  1. verification: 로딩된 바이트 코드가 Java Virtual Machine Specification에 명세된 대로 이진 표현이 구조적으로 올바른지 확인합니다.
  2. preparation: 클래스 또는 인터페이스에 정의된 정적 필드를 생성하고 해당 필드를 기본값으로 초기화 작업을 진행하고 메서드에 대한 제약 조건을 적용합니다.
  3. resolution: Runtime Constant pool에 심볼릭 레퍼런스를 구체적인 값을 동적으로 결정하는 역할을 합니다.

javap 명령어에 -v 옵션을 주어 바이트 코드를 디어셈블하게 되면 Class Loader의 Linking 과정 중 resolution 단계에 등장하는 Runtime Constant pool의 심볼릭 레퍼런스를 보실 수 있습니다. 심볼릭 레퍼런스는 상수 풀 내의 항목을 참조하기 위해 사용되며 #번호 부분은 Constant pool의 인덱스입니다. 이 인덱스 번호를 통해 해당 클래스에서 사용되는 메세드 및 필드를 참조하게 됩니다.

Initiallization

클래스 변수들을 설정된 값으로 초기화하는 작업을 합니다.

 

4.  Execution Engine

Class Loader를 통해 Runtime Data Areas에 올라간 바이트 코드는 기계가 바로 실행할 수 없는 코드입니다.

Execution Engine은 이러한 바이트 코드를 명령어 단위로 실행해 컴퓨터가 이해할 수 있는 기계어로 해석하고 실행하는 작업을 합니다.

 

바이트 코드는 1바이트의 OpCode와 추가 피연산자(Operand)로 구성되어 있으며 하나의 OpCode를 가져와서 피연산자와 함께 작업을 수행 후 다음 OpCode를 수행하는 방식으로 동작합니다.

 

JVM에 대해 알아보면서 Operation Code와 Operand에 대해서 처음 알게 되었는데 다음번에 기회가 된다면 추가적으로 공부를 해봐야겠습니다.. 자바 바이트코드의 OpCode와 Operand에 대해서 더 알고싶으신 분들은 밑의 링크를 참고해 주세요.

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.11

 

Chapter 3. Compiling for the Java Virtual Machine

The Java Virtual Machine machine is designed to support the Java programming language. Oracle's JDK software contains a compiler from source code written in the Java programming language to the instruction set of the Java Virtual Machine, and a run-time sy

docs.oracle.com

 

Execution Engine은 두 가지 방식으로 바이트 코드를 기계어로 해석하게 됩니다.

  1. Interpreter: 바이트 코드를 명령어를 하나씩 읽어서 해석하고 실행합니다. 명령어를 하나씩 해석하고 실행하기 때문에 실행이 느리다는 단점을 가지고 있습니다.
  2. JIT Compiler(Just-In-Time Compiler): interpreter 방식의 단점을 보완하기 위해 나온 컴파일 방식입니다. JVM은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크해서 일정 기준이 넘어가면 바이트 코드 전체를 컴파일 하여 네이티브 코드로 변경하고 캐시에 보관하여 더 이상 인터프리팅하지 않고 캐싱된 네이티브 코드를 직접 실행하는 방식입니다. 

Garbage Collector는 Heap 메모리 영역에서 더 이상 사용하지 않는 메모리를 자동으로 회수해주는 작업을 하게 되는데 GC에 관련된 내용은 좀 더 깊이 공부 후 포스팅을 해보도록 하겠습니다.

 

5.  Runtime Data Areas

프로그램 실행 중에 사용되는 메모리 영역입니다. Method Area와 Heap 영역은 JVM 시작 시 생성되고 JVM이 종료될 때만 삭제되며 모든 스레드가 공유해서 사용하는 영역입니다. JVM Stack, PC Register, Native Method Stack은 스레드마다 생성되는 영역이며 스레드가 생성되고 종료될 때 삭제됩니다.

 

Heap

모든 스레드가 공유하는 영역이며 인스턴스 및 배열 타입 등 Reference Type이 런타임 시 동적으로 할당되는 영역입니다.

Heap 영역에서 더 이상 참조되지 않은 메모리는 GC의 대상입니다. Heap의 크기는 동적으로 확장되거나 축소될 수 있으나 너무 많은 메모리를 사용하는 경우 OutOfMemoryError로 인해 프로그램이 종료될 수 있습니다.

 

Method Area

이 영역도 모든 스레드가 공유하는 영역이며 Runtime constant pool, static 변수, 필드 및 메서드, 생성자 등 바이트 코드를 보관하는 영역입니다. 이 영역에 대한 GC 수행은 JVM의 선택사항이기 때문에 GC 대상이 될 수도 있고 안 될 수도 있습니다.

 

PC Register

스레드마다 생성되는 영역이며 해당 스레드가 현재 실행 중인 JVM 명령어에 주소를 포함합니다.

 

JVM Stacks

스레드마다 생성되는 영역이며 stack frame에는 Local variables와 Operand Stacks 그리고 Runtime constant pool의 참조를 갖게 됩니다.

 

Native Method Stacks

스레드마다 생성되는 영역이며 자바 언어 이외의 언어로 작성된 메서드를 지원하기 위한 스택입니다.

자바 언어 이외의 언어로 만들어진 애플리케이션과 상호 작용할 수 있는 JNI(Java Native Interface)가 사용되면 Native Methode Stack에 쌓이게 됩니다.

JVM Stacks와 Native Method Stacks는 스레드가 사용할 수 있는 스택의 사이즈가 넘어가면 StackOverflowError가 발생하여 프로그램이 종료가 됩니다. 또한 스택의 크기는 동적으로 확장할 수 있지만 확장 시 메모리가 부족하게 되면 OutOfMemoryError가 발생하여 프로그램이 종료됩니다.

 

6.  reference

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-3.html#jvms-3.11

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-2.html#jvms-2.5

https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-5.html

https://d2.naver.com/helloworld/1230

https://www.javacodegeeks.com/2018/04/jvm-architecture-execution-engine-in-jvm.html#google_vignette

728x90

'BackEnd > Java' 카테고리의 다른 글

자바 Enum 타입 속 모든 비밀: 정의, 컴파일러, 싱글톤  (0) 2023.10.25
BigDecimal 사용 이유  (0) 2023.10.19
equals() 메서드와 hashCode() 메서드  (0) 2023.09.16
Stream  (0) 2023.08.20
람다 표현식  (0) 2023.08.16