본문 바로가기
정리

[Java] JVM 정리 (JVM의 개념, 실행과정, 구조)

by baau 2023. 7. 12.

JDK vs JRE

JDK (Java Development Kit)

  • 자바를 개발 시 필요한 라이브러리와 javac, javadoc 등의 개발 도구 포함
  • 자바 프로그램을 실행시키기 위한 JRE(Java Runtime Environment) 포함
  • Java SE (Java Standard Edition)
    • 가장 기본이 되는 표준 에디션의 자바 플랫폼으로 자바 언어의 핵심 기능 제공
  • Java EE (Java Enterprise Edition)
    • 대규모 기업용 에디션, SE 확장판

 

JRE (Java Runtime Environment)

  • JVM과 자바 프로그램을 실행시킬 때 필요한 라이브러리 API를 함께 묶어서 배포되는 패키지
  • JRE은 기본적으로 JDK에 포함되어 있어 JDK를 설치하면 함께 설치된다.

 


JVM (Java Virtual Machine)

  • 자바 가상 머신의 약자로, 자바를 실행하는 프로그램
    • 자바 언어뿐만 아니라 코틀린, 스칼라 언어에서도 JVM 동작 방식을 따른다.
  • JVM을 사용하면 자바 프로그램을 모든 플랫폼에서 제약 없이 동작할 수 있다.
    • OS에 종속적이지 않아, 운영체제로부터 독립적으로 프로그램을 제약 없이 실행할 수 있다. ⇒ 이식성이 좋다.
    • Java 언어로 작성한 소스파일은 운영체제가 직접 실행하는 것이 아닌, JVM을 거쳐서 운영체제와 상호작용을 하게 된다.
    • 컴파일된 코드와 하드웨어/OS 사이에서, 하드웨어/OS 환경에 알맞게 JVM이 바이트 코드로 변환해 주기 때문이다.
  • 자바 프로그램과는 달리 자바 가상 머신(JVM)은 운영체제에 종속적이므로, 각 운영체제에 맞는 자바 가상 머신을 설치해야 한다.
  • Java는 C언어와 달리 두 번의 컴파일 과정으로 인해 속도의 문제가 발생한다.
    • 이를 보완하기 위해 JIT 컴파일러 등장
    • 필요한 부분만을 기계어로 바꾸어 줌으로써 성능 향상을 가져오도록 했지만, C언어의 실행 속도는 따라잡지 못한다.
    • 게임이나 임베디드에서 C계열 언어를 사용하는 이유가 바로 이 때문이다.

 

JVM 실행 과정

  1. JVM은 OS로부터 메모리(Runtime Data Area)를 할당받는다.
  2. 컴파일러(javac)는 자바 소스코드(.java)를 읽어, JVM가 이해할 수 있는 바이트 코드 (.class)로 변환한다.
  3. Class Loader는 동적 로딩을 통해 필요한 클래스들을 로딩 및 링크하여, Runtime Data Area로 로딩한다.
  4. 로딩된 클래스는 Execution Engine을 통해 해석 및 실행되며, Garbage Collector의 작동과 Thread 동기화가 이루어진다.

 

JVM의 구조

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

 

1. 클래스 로더 (Class Loader)

  • JVM 내로 클래스 파일 (*.class)을 동적으로 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈
    • 동적 로딩 : 클래스를 메모리에 한 번에 로딩하지 않고, 애플리케이션에서 필요한 경우 동적으로 메모리에 적재한다.
  • 로드된 바이트 코드를 엮어서 JVM의 메모리 영역인 Runtime Data Area에 배치한다.

 

2. 실행 엔진 (Execution Engine)

  • 클래스 로더를 통해 Runtime Data Area에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.
  • 바이트 코드를 실제로 JVM 내부에서 컴퓨터가 실행할 수 있는 형태로 변경한다.
  • 실행 엔진은 인터프리터와 JIT 컴파일러 두 가지 방식을 혼합하여 바이트 코드를 실행
    • 인터프리터
      • 바이트 코드 명령어를 하나씩 읽어서 해석하고 바로 실행
      • 같은 메서드라도 여러 번 호출이 된다면 매번 해석하고 수행해야 하므로 전체적인 속도가 느리다.
    • JIT 컴파일러
      • 인터프리터의 단점을 보완하기 위해 도입
      • 반복되는 코드를 발견하여 바이트 코드 전체를 컴파일하여 Native Code로 변경하고 이후에는 해당 메서드를 인터프리팅 하지 않고 캐싱해 두었다가 네이티브 코드로 직접 실행하는 방식
      • 하나씩 인터프리팅하여 실행하는 것이 아니라, 컴파일된 네이티브 코드를 실행하는 것이기 때문에 전체적인 실행 속도는 개선할 수 있다.
      • 바이트 코드를 Native Code로 변환하는 데에도 비용이 소모되므로, 모든 코드에 대해서 JIT 컴파일러 방식을 사용하지 않고 인터프리터 방식을 사용하다 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행하는 식으로 진행
  • 가비지 컬렉션
    • Heap 메모리 영역에서 사용하지 않는 메모리를 자동으로 회수한다.

 

3. 런타임 데이터 영역  (Runtime Data Area)

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터를 적재하는 영역

  • Method Area
    • JVM이 시작될 때 생성되는 영역이며, 프로그램이 종료될 때 해제된다.
    • 자바 프로그램 시작 시 초기화되는 static 변수, static 메서드, 클래스 정보만 저장된다.
    • 모든 스레드에서 공유하는 영역
    • Runtime Constant Pool
      • 클래스/인터페이스가 로딩될 때 Method Aread에 할당되는 자료구조
      • 각 클래스/인터페이스마다 별도의 constant pool 테이블이 존재, 클래스 생성할 때 참조해야 할 정보들을 상수로 가지고 있는 영역
      • Constant Pool을 통해 메서드나 필드의 실제 메모리 상 주소를 찾아 참조

 

  • Heap Area
    • 런타임 시 동적으로 할당된 데이터를 저장하는 영역
      • new 연산자로 생성되는 클래스와 인스턴스 변수, 배열 타입 등 Reference Type이 저장되는 영역
    • 모든 스레드에서 공유하는 영역
    • GC(Garbage Collector)의 대상이 되어, 참조되지 않는 객체는 자동으로 제거된다.
    • Young(Eden, survivor 0, survivor 1), Old, Permanent 영역으로 구분된다.

 

  • Stack Area
    • 메서드 호출 시 메서드의 지역변수, 매개변수, 리턴 값 및 연산 중 발생하는 임시 데이터를 저장하는 영역
    • 메서드 호출 시마다 각각의 스택 프레임이 생성되고, 메서드가 종료되면 프레임별로 삭제된다.
    • 각 스레드마다 하나씩 존재하며, 스레드가 초기화될 때 할당된다.
    • 스레드가 종료되면 해당 스레드의 Stack도 소멸된다.

 

  • PC Register
    • 스레드가 시작될 때 생성되며, 현재 수행 중인 JVM 명령어 주소를 저장하는 공간
    • 스레드마다 하나씩 존재하며, 현재 수행 중인 명령어의 주소를 가리킨다.

 

  • Native Method Stack
    • 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역
    • 자바 외의 JIT 컴파일러에 의해 변환된 C/C++로 작성된 Native Code를 실행하기 위한 영역
    • JNI(Java Native Interface)를 통해 호출되는 C/C++ 함수의 매개변수, 지역변수 등을 저장하는 영역

 

4. 네이티브 메서드 인터페이스 (Native Method Interface)

  • 자바가 다른 언어로 만들어진 애플리케이션과 상호 작용할 수 있는 인터페이스를 제공하는 프로그램
  • JVM이 Native Method를 적재하고 수행할 수 있도록 한다.
  • 하지만 실질적으로 제대로 동작하는 언어는 C/C++ 정도밖에 없다고 한다.

 

5. 네이티브 메서드 라이브러리 (Native Method Library)

  • C, C++로 작성된 라이브러리
  • 만일 헤더가 필요하면 JNI는 이 라이브러리를 로딩하여 실행한다.

 

참고내용