# Java Virtual Machine(JVM)

\


## 개요(JDK, JRE, JVM)

![](https://velog.velcdn.com/images/sgwon1996/post/f133fb06-0be5-4d28-96b1-ee28bba9604e/image.png)

* JDK(Java Development Kit)
  * 자바 개발 도구로, JRE + 개발에 필요한 툴
  * 자바 개발 환경으로 자바 어플리케이션을 개발하기 위해 필요한 도구를 제공함
  * 자바 언어를 바이트 코드로 컴파일 해주는 자바 컴파일러(javac), 자바 클래스 파일을 해석해주는 역 어셈블리어(javap) 등 존재
  * [Tools and Commands Reference](https://docs.oracle.com/en/java/javase/11/tools/tools-and-command-reference.html)
* JRE(Java Runtime Environment)
  * 자바 실행 환경으로, 자바 애플리케이션을 실행할 수 있도록 구성된 배포판
  * JVM과 핵심 라이브러리 및 자바 어플리케이션 실행에 필요한 파일들을 포함함
* JVM(Java Virtual Machine)
  * 자바 어플리케이션을 실행하는 가상 머신

\


### VM

> 가상머신: 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것

#### 장점

* 이식성
  * 플랫폼과 운영체제에 독립적으로 동작할 수 있도록 함
  * 개발한 애플리케이션은 VM 위에서 실행되므로, 어떤 운영체제나 플랫폼에서도 동일하게 작동할 수 있음
  * 이식성이 높아져서 애플리케이션을 다양한 환경에서 실행하거나 배포하는 데 유리함
* 보안
  * 보안을 강화할 수 있는 장치를 제공
  * VM은 코드 실행과 메모리 관리를 감독하며, 액세스 제어와 코드 검증 등의 보안 기능을 제공함
  * 애플리케이션을 격리하여 악성 코드의 실행을 방지하고, 안전한 실행 환경을 제공함
* 자원 관리
  * 메모리 할당, 가비지 컬렉션, 스레드 관리 등을 자동으로 처리하여 개발자가 직접 관리해야 하는 부담을 줄여줌
  * 이를 통해 안정성과 성능을 향상시칼 수 있음
* 다중 언어 지원
  * JVM은 Java뿐만 아니라 Kotlin, Scala, Groovy 등 다른 JVM 언어들을 실행할 수 있음
  * 이는 개발자에게 언어 선택의 자유를 주고, 기존 언어와 새로운 언어 간의 상호 운용성을 제공함

\


#### 단점

* 성능 오버헤드
  * VM은 어플리케이션 실행을 위해 추가적인 추상화 계층을 도입하므로 성능에 일정한 오버헤드가 발생함
  * 일부 언어나 애플리케이션에서는 이 오버헤드가 큰 문제가 될 수 있음
  * 최근 VM은 최적화 기술을 통해 이러한 성능 문제를 완화하고 있음
* 자원 사용
  * VM은 실행을 위해 일정한 시스템 자원이 필요함
  * 애플리케이션을 실행할 때 이에 대한 고려가 필요하며, 가용한 자원에 따라 애플리케이션 성능에 영향을 줄 수 있음
* 제한된 접근
  * VM은 운영체제 위에서 동작하기 때문에, 특정 운영체제 레벨의 기능에 직접 접근하기 어려울 수 있음
  * 예를 들어, 시스템 하드웨어에 직접 접근해야 하는 애플리케이션에는 추가 작업이 필요할 수 있음
* 배포 크기
  * VM을 사용하면 애플리케이션과 함께 VM도 함께 배포해야 하기 때문에 애플리케이션의 배포 크기가 커질 수 있음
  * 최신의 VM은 모듈화와 최적화 기술을 사용하여 이 문제를 완화시키고 있음

\
\


## JVM이란?

* 자바를 실행하기 위한 가상 기계
* 운영체제에 종속받지 않고, CPU가 Java를 인식하고 실행할 수 있게 하는 가상 컴퓨터
* 소프트웨어와 하드웨어 사이에서 중개자 역할을 수행하여 자바 애플리케이션을 다른 운영체제 또는 플랫폼에서 실행할 수 있도록 함

\


### Java 애플리케이션 실행 과정

<div align="left"><img src="https://github.com/jmxx219/CS-Study/assets/52346113/fa7dd397-30d3-47a3-9be8-0dc93b9a2a9c" alt="" width="550"> <img src="https://oopy.lazyrockets.com/api/v2/notion/image?src=https%3A%2F%2Fs3-us-west-2.amazonaws.com%2Fsecure.notion-static.com%2F8ffbd66c-2447-48e8-a463-1063aac1e19b%2FUntitled.png&#x26;blockId=60c574d2-4b6c-4864-b401-4d9d20d4fbb5" alt="" width="120"></div>

1. 소스 코드 작성
   * Java 소스 코드, 즉 원시 코드(`*.java`)는 CPU가 인식하지 못하기 때문에 기계어로 컴파일을 해주어야 함
   * 이때, Java는 JVM이라는 가상 머신을 거쳐서 OS에 도달하기 때문에 OS가 인식할 수 있는 기계어로 바로 컴파일 되지 않음
     * 일반 애플리케이션의 코드는 OS만 거치고 하드웨어로 전달되지만, Java 애플리케이션은 중간에 JVM을 거침
2. `Java compiler`가 `*.java` 파일을 `*.class`로 변환함
   * 클래스 파일은 JVM이 인식할 수 있는 자바 바이트 코드 파일임
   * Java compiler는 JDK를 설치하면 `javac.exe`라는 실행 파일 형태로 존재함
     * `javac` 명령어를 통해 `*.java`를 `*.class`로 컴파일 할 수 있음
3. `JVM`은 클래스 파일의 `바이트 코드`를 해석하여 `기계어(Binary Code)`로 변환하고 프로그램을 수행함
   * 변환된 바이트코드는 기계어가 아니기 때문에 OS에서 바로 실행되지 않음
     * JVM이 해당 바이트코드를 OS가 이해할 수 있도록 해석하는 역할을 담당함
   * 결국 JVM은 하드웨어/OS 사이 중간에서 하드웨어/OS 환경에 맞게 바이트코드를 기계어(Binary Code)로 변환하는 역할을 함
   * Java 애플리케이션은 JVM하고만 상호작용 하기 때문에 OS가 달라지더라도 프로그램 변경없이 실행이 가능함
     * OS에 종속적이지 않고, Java 파일 하나만 만들면 어느 디바이스든 JVM 위에서 실행할 수 있음

\


> 바이트코드: 특정 하드웨어가 아닌 가상 머신에서 돌아가는 실행 프로그램을 위한 이진 표현법

\
\


## JVM 구조

![](https://blog.kakaocdn.net/dn/d2DOH1/btsp19Tlwop/nE8FiQHkO0kwmJIVX4Z98k/img.png)

### 동작 방식

1. 자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당받음
2. 자바 컴파일러(`javac`)가 자바 소스코드(`*.java`)를 자바 바이트 코드(`*.class`)로 컴파일 함
3. `Class Loader`는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크 하여 `Runtime Data Area`(실질적인 메모리를 할당 받아 관리하는 영역)에 올림
4. `Runtime Data Area`에 로딩된 바이트 코드는 `Execution Engine`을 통해 해석됨
5. 이 과정에서 `Execution Engine`에 의해 `Garbage Collector`의 작동과 `Thread` 동기화가 이루어짐

\


### 구성 요소

* 클래스 로더(Class Loader)
* 실행 엔진(Execution Engine)
  * 인터프리터(Interpreter)
  * JIT 컴파일러(Just-in-Time)
  * 가비지 콜렉터(Garbage collector)
* 런타임 데이터 영역 (Runtime Data Area)
  * 메소드 영역
  * 힙 영역
  * PC Register
  * 스택 영역
  * 네이티브 메소드
* JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)
* 네이티브 메소드 라이브러리 (Native Method Library)

\


### ◽ 클래스 로더(Class Loader)

> 자바는 런타임에 클래스를 처음으로 참조할 때 해당 클래스를 로드하고 링크하는 특징이 있음\
> 이 동적 로드를 담당하는 부분이 JVM의 클래스 로더

* JVM 내로 클래스 파일(`*.class`)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈
  * 즉, 로드된 바이트 코드(`*.class`)들을 엮어서 JVM의 메모리 영역인 Runtime Data Areas에 배치함
* 클래스 파일의 로딩 과정 3단계(`Loading` → `Linking` → `Initialization`)
  * `Loading(로딩)`: 클래스 파일을 가져와서 JVM의 메모리에 로드함
  * `Linking(링크)`: 클래스 파일을 사용하기 위해 검증하는 과정
    * Verifying(검증) : `.class` 파일 형식이 유효한지 체크함
    * preparing(준비) : 클래스가 필요로 하는 메모리를 할당함
    * Resolving(분석) : 심볼릭 메모리 레퍼런스를 메모리 영역에 있는 실제 레퍼런스로 교체함
  * `Initialization(초기화)` : 클래스 변수들을 적절한 값으로 초기화함(static 변수 값 할당 등)

\


### ◽ 실행 엔진(Execution Engine)

* 클래스 로더에 의해 Runtime Data Area에 적재된 바이트 코드들을 기계어로 변경해 명령어 단위로 실행하는 역할
  * 자바 바이트 코드(\*.class)는 기계가 바로 수행할 수 있는 언어보다는 가상 머신이 이해할 수 있는 중간 레벨로 컴파일된 코드임
  * 따라서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경해줌
* 위 수행과정에서 실행 엔지은 두 가지 방식을 혼합하여 바이트코드(명령어)를 실행함
  * 인터프리터(Interpreter)
    * 바이트 코드 명령어를 하나씩 읽어서 해석하고 바로 실행함
    * JVM 안에서 바이트 코드는 기본적으로 인터프리터 방식으로 동작함
    * 다만 같은 메서드라도 여러 번 호출되면 매번 해석하고 수행해야 하기 때문에 전체적인 속도가 느림
  * JIT(Just-In-Time) 컴파일러
    * Interpreter의 단점을 보완하기 위해 도입된 방식
    * 반복되는 코드를 발견하여 바이트 코드 전체를 컴파일하여 Native Code로 변경하고, 이후에는 해당 메서드를 더 이상 인터프리팅하지 않고 캐싱해두었다가 네이티브 코드로 직접 실행하는 방식
    * 하니씩 인터프리팅하여 실행하는 것이 아닌, 컴파일된 네이티브 코드를 실행하기 때문에 전체적인 실행 속도는 인터프리팅 방식보다 빠름
    * 하지만 바이트 코드를 네이티브 코드로 변환하는데 비용이 소요되기 때문에 JVM은 모든 코드를 JIT 컴파일러 방식으로 실행하지 않음
      * 인터프리터 방식으로 사용하다가 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행하는 방식으로 진행함
* 더 이상 참조되지 않는 객체를 모아서 정리하는 [GC(Garbage Collector)](garbage-collection) 존재
  * JVM은 Garbage Collector를 통해 자동화된 메모리 관리 기능을 제공함

\


> 네이티브 코드: JAVA에서 부모가 되는 C언어나, C++, 어셈블리어로 구성된 코드

\


### ◽ 런타임 데이터 영역 (Runtime Data Area)

* JVM의 메모리 영역으로, 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역
* 6가지 영역 존재
  * 스택(stack) 영역
    * 지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값등이 생성되는 영역
    * 클래스 수준의 정보를 저장하고 공유하는 자원
  * PC Register
    * 쓰레드가 생성될 때마다 생성되는 영역으로, 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역
    * 현재 수행 중인 JVM 명령의 주소를 가짐
  * 네이티브 메소드 스택 영역
    * 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역으로, 보통 C/C++등의 코드를 수행하기 위한 스택(`JNI`)
    * 바이트코드가 아닌 실제 수행할 수있는 기계어로 작성된 프로그램을 실행시키는 영역
  * 힙(heap) 영역
    * `new` 키워드로 생성된 객체와 배열이 생성되는 영역
    * 메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 참조되지 않는 메모리를 확인/제거하는 영역
  * 메소드 영역
    * 모든 스레드가 공유하는 영역으로, JVM이 시작될 때 생성됨
    * JVM이 읽어들인 클래스나 필드, 메서드 정보 등 초기화되는 대상을 저장하는 공간
  * Runtime Constant Pool
    * 메소드 영역에 존재하는 별도의 관리 영역으로, 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 함

\


### ◽ JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)

* JNI는 자바가 다른 언어로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스 제공하는 프로그램
* JNI는 JVM이 Native Method를 적재하고 수행할 수 있도록 함
* 실질적으로 제대로 동작하는 언어는 C와 C++ 정도만 존재함

\


### ◽ 네이티브 메소드 라이브러리 (Native Method Library)

* C, C++로 작성된 라이브러리를 칭함

\
\


## JVM 기능

* 자바 애플리케이션 실행 환경 제공
  * 자바 소스 코드(.java 파일)는 컴파일되어 바이트 코드(.class 파일)로 변환되고, JVM은 이 바이트 코드를 해석하고 실행함
* 메모리 관리
  * 메모리 할당, 해제, 가비지 컬렉션 등의 작업을 처리하여 프로그래머가 명시적으로 메모리를 관리할 필요 없이 효율적인 메모리 사용이 가능하도록 함
* 가상 머신 지원
  * JVM은 자바 애플리케이션을 다양한 운영체제와 하드웨어 플랫폼에서 실행할 수 있도록 함
  * JVM은 운영체제와 하드웨어에 종속적인 부분을 처리하고, 자바 애플리케이션이 동일한 방식으로 동작하도록 보장함
* 보안 관리
  * 애플리케이션 실행 중에 액세스 제어, 클래스 로딩, 코드 검증 등의 작업을 수행하여 악의적인 동작을 방지하고 안전한 실행 환경을 제공함
* 예외 처리
  * 예외는 프로그램 실행 중에 발생하는 오류나 예기치 않은 상황을 나타내며, JVM은 이러한 예외를 적절히 처리하고 애플리케이션의 비정상적인 종료를 방지함

\


> JVM은 자바의 핵심 원칙 중 하나인 `Write Once, Run Anywhere`를 실현하는데 중요한 역할을 한다. 이는 자바 애플리케이션이 플랫폼에 독립적으로 작성되고, JVM을 통해 다양한 환경에서 실행될 수 있다는 의미이다. JVM은 자바의 이식성과 유연성을 보장하며, 자바가 널리 사용되는 이유 중 하나이다.

\
\


## JVM 언어

* JVM은 주로 자바 언어의 실행을 위해 설계되었지만, 다른 언어를 JVM 위에 올릴 수 있음
* 이를 가능하게 하는 주요 요소는 `JVM 언어` 또는 `JVM 기반 언어`라고 불리는 언어들
  * 이러한 언어는 자바 가상 머신에서 실행되는 바이트 코드 형태로 컴파일되며, JVM이 해당 언어를 해석하고 실행할 수 있도록 함

\


### JVM 언어 종류

* Kotlin
  * 자바와 상호 운용이 가능한 정적 타입의 프로그래밍 언어
  * 안드로이드 애플리케이션 개발에도 널리 사용됨
* Scala
  * 객체 지향 및 함수형 프로그래밍을 지원하는 다중 패러다임 언어
  * 대규모 애플리케이션 개발에 널리 사용되며, 스파크(Spark)와 같은 대용량 데이터 처리 프레임워크의 기본 언어로 사용되기도 함
* Groovy
  * 자바와 유사한 문법을 가지며, 동적 타이핑을 지원하는 스크립트 언어
  * 자바와의 상호 운용성이 우수하며, Gradle 빌드 도구의 스크립팅 언어로도 널리 사용됨
* 이외에도 JRuby(루비), Jython(파이썬), Clojure(클로저) 등의 다른 언어도 JVM 위에서 실행될 수 있음
  * JVM 언어를 사용하면 자바 플랫폼의 다양한 기능과 라이브러리를 활용하면서 다른 언어의 장점을 살릴 수 있음

\


#### ➕ JVM 계열 언어를 일반적으로 컴파일해서 사용하는 것은 불가능함

* JVM 언어는 주로 바이트 코드로 컴파일되어 JVM에서 실행됨
  * 이는 JVM 언어가 자바 가상 머신에서 동작하도록 설계된 특성 때문
  * 따라서 JVM 언어를 일반적인 컴파일 언어처럼 기계어로 직접 변환하여 다른 환경에서 실행하는 것은 일반적으로 지원되지 않음
* 그러나 JVM 언어의 일부에서는 Ahead-of-Time (AOT) 컴파일러를 사용하여 바이트 코드를 네이티브 코드로 변환하는 기능을 제공하는 경우도 있음
  * 이러한 기능을 사용하면 JVM 언어로 작성된 애플리케이션을 특정 플랫폼에 네이티브 바이너리로 컴파일하여 실행할 수 있음
  * 예를 들어, GraalVM은 JVM 언어를 AOT 컴파일하여 네이티브 이미지로 변환하는 기능을 제공함
* 또한, 일부 JVM 언어는 자바와의 상호 운용성을 위해 자바 언어로 변환될 수 있음
  * 이는 해당 언어의 소스 코드를 자바 소스 코드로 변환한 후, 자바 컴파일러를 사용하여 자바 바이트 코드로 컴파일하는 방식
  * 이렇게 변환된 자바 바이트 코드는 JVM에서 실행할 수 있음
* 따라서 일반적으로 JVM 언어는 JVM에서 실행하기 위해 바이트 코드로 컴파일되며, 다른 플랫폼에서 직접 컴파일되어 실행되는 것은 일반적으로 지원되지 않음

\
\


## JVM과 내부에서 실행되고 있는 프로그램의 관계

* JVM은 자바 애플리케이션을 실행하기 위한 가상 머신
  * 자바 애플리케이션은 JVM 위에서 실행되며, 이러한 관계에서 `부모 프로세스 - 자식 프로세스`와 비슷한 관계를 가질 수 있음
* 일반적으로 JVM은 운영체제에서 실행 중인 하나의 프로세스로 간주됨
  * JVM은 자체적으로 스레드, 메모리, 리소스 등을 관리하며, 이러한 자원을 사용하여 자바 애플리케이션을 실행함
  * 자바 애플리케이션은 JVM 내에서 동작하는 여러 개의 스레드로 실행되는데, 이 스레드들은 JVM의 자식 프로세스로 간주될 수 있음
* 하지만 `부모 프로세스 - 자식 프로세스` 관계는 주로 운영체제 수준의 관점에서 사용되는 용어이며, JVM은 이러한 관계를 직접적으로 반영하지는 않음
  * JVM은 운영체제와는 독립적으로 동작하며, 자바 애플리케이션을 실행하는 데 필요한 내부 처리를 담당함
* 따라서, JVM과 자바 애플리케이션 간의 관계를 `부모 프로세스 - 자식 프로세스` 관계로 설명하는 것은 일반적인 운영체제 용어와의 비유로 이해할 수 있지만, 엄밀한 용어적 정의는 아님
  * JVM은 자바 애플리케이션 실행을 위한 실행 환경을 제공하고, 자바 애플리케이션은 JVM 내에서 실행되는 독립적인 단위로 간주됨

\
\


### Ref

* [JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가.](https://catsbi.oopy.io/df0df290-9188-45c1-b056-b8fe032d88ca)
* [JVM 내부 구조 & 메모리 영역](https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8)
