Java - JVM, JDK, JRE

java를 조금 더 깊게 알고 싶어요.

Posted by Yan on April 4, 2022

JVM, JDK, JRE의 차이를 알아보자.

JVM : Java Virtual Machine

  • 자바 가상 머신
  • 자바 바이트코드 (.class파일)를 인터프리터와 JIT 컴파일러가 OS에 특화된 코드로 변환하여 실행
  • JVM 밴더: 오라클, 아마존, Azul 등
  • 특정 플랫폼에 종속적

JRE : Java Runtime Environment

  • JRE = JVM + Library
    • 핵심 라이브러리, 자바 런타임 환경에서 사용하는 프로퍼티 세팅, 리소스 파일 등을 가지고 있음
  • 자바 애플리케이션을 실행할 수 있도록 구성된 배포판
  • 개발관련 도구는 제공 되지 않음(컴파일러 javac가 JRE에 포함되어 있지 x)

JDK : Java Development Kit

  • JDK = JRE + 개발에 필요한 툴
    • 개발 툴 : javadoc, jar, javap 등등
  • java11부터 module system 도입. JRE를 따로 제공하지 않게 됨.
  • 소스 코드 작성시 사용하는 자바 언어는 플랫폼에 독립적

JVM의 구조

Stack, PC, Native Method Stack : 특정 쓰레드에 국한된다.
Heap, Method : 공유자원

클래스 로더 시스템

클래스 로더 시스템은 .class에서 바이트 코드를 읽고 메모리에 저장한다.

loading -> linking -> initialization 순서대로 진행

1. loading : 클래스를 읽어오는 과정

  • 클래스 로더가 .class파일을 읽는다 -> 그 내용에 따라 적절한 바이너리 데이터를 만든다 -> method 영역에 저장한다.
  • 메소드 영역에 저장하는 데이터는
    • FQCN : Fully Qualified Class Name
    • 클래스인지, 인터페이스인지, 이넘인지
    • 메소드와 변수
  • 로딩이 끝나면 해당 클래스 타입의 Class 객체를 생성하여 heap 영역에 저장

로딩 클래스 로더의 종류

  • 부트스트랩 클래스 로더 (BootLoader)
    • JAVA_HOME\lib에 있는 코어 자바 API 제공.
    • 최상위 우선순위를 가진 클래스 로더
    • 네이티브 코드로 구성되어 있음
  • 플랫폼 클래스 로더 (PlatformClassLoader)
    • JAVA_HOME\lib\ext 폴더 또는 java.ext.dirs 시스템 변수에 해당하는 위치에 있는 클래스를 읽음
  • 애플리케이션 클래스 로더 (AppClassLoader)
    • application classpath(application 실행할 때 주는 -classpath 옵션 또는 java.class.path 환경 변수의 값에 해당하는 위치)에서 클래스를 읽음

2. linking : 레퍼런스를 연결하는 과정

  • Verify, Prepare, Resolve 세 단계
  • Verify : .class 파일 형식이 유효한지 체크
  • Prepare : 클래스 변수(static 변수)와 기본값에 필요한 메모리 준비
  • Resolve(optional) : symbolic memory reference를 메소드 영역에 있는 실제 레퍼런스로 교체 (실제 heap에 들어있는 인스턴스를 가리키도록 하는 것)

3. Initialization : static 값들을 초기화하고 변수에 할당하는 과정

  • static 변수의 값을 할당. static 블럭이 있다면 이때 실행된다.

런타임 데이터 영역 (메모리)

Method

  • 클래스 수준의 정보 저장 (클래스 이름, 부모 클래스 이름, 클래스 경로, 메소드, 변수)
  • JVM당 하나만 생성된다.
  • 다른 영역에서도 참조 가능하다. 인스턴스 생성에 필요한 정보도 존재하기 때문에 JVM의 모든 Thread들이 Method Area를 공유한다.(공유자원)
  • JVM의 다른 메모리 영역에서 해당 정보에 대한 요청이 오면, 실제 물리 메모리 주소로 변환해서 전달해준다.
  • JVM 구동 시작 시에 생성되고, 종료할 때까지 유지되는 공통 영역이다.

Heap

  • 객체를 저장. (공유자원)
  • 코드 실행을 위한 Java로 구성된 객체 및 JRE 클래스들이 탑재된다.
  • 문자열에 대한 정보를 가진 String pool, 실제 데이터를 가진 인스턴스, 배열 등이 저장된다.
  • JVM당 하나만 생성된다.
  • heap영역이 가진 데이터는 모든 Java Stack 영역에서 참조되어 Thread간 공유가 된다.
  • heap영역이 가득 차면 OutOfMemoryError를 발생시킨다.
  • 참조되지 않는 인스턴스와 배열에 대한 정보도 얻을 수 있어, GC의 주 대상이 된다.

Stack

  • 각 Thread별로 따로 할당되는 영역.
  • heap 메모리 영역보다 비교적 빠르다.
  • Thread 별로 메모리를 따로 할당하기 때문에 동시성 문제에서 자유롭다.
  • 쓰레드마다 런타임 스택을 만든다. 그 안에 메소드 호출을 스택 프레임이라는 블럭으로 쌓는다. 쓰레드 종료시 런타임 스택도 사라진다.
    • 각 Thread들은 메소드를 호출할 때마다 프레임이라는 단위를 push하게 된다.
    • 메소드가 마무리되며 결과를 반환할 시 해당 프레임은 stack으로부터 pop된다.
    • 프레임은 메소드에 대한 정보를 가지고 있는 local variable, operand stack, constant pool reference로 구성
    • local variable : 메소드 안의 지역 변수들을 가지고 있다.
    • operand stack : 메소드 내 연산을 위한 바이트 코드 명령문들이 들어있다.
    • constant pool refence : 참조를 위한 공간

PC (Program Counter) Register

  • 쓰레드마다 각각 자신만의 PC Register를 가지고 있다. 쓰레드 내에서 현재 실행할 스택 프레임을 가리키는 포인터가 생성된다.
  • 쓰레드별로 동시에 실행하는 환경이 보장되어야 하니, 최근에 실행중인 JVM에서 명령어 주소값을 저장할 공간이 필요한데, 이 공간을 PC Register가 관리하여 추적해준다.
  • 실행했던 메소드 != 네이티브이면 JVM에서 사용된 명령의 주소를 저장하게 된다.

Native Method Stacks

  • Native Method: 다른 프로그래밍 언어로 작성된 메소드 (자바로 구성된 코드만을 사용할 수 없는 시스템 자원이나 API이용시)
  • Native Method Stacks: 자바로 작성되지 않은 메소드를 다루는 영역
  • JNI가 실행

실행 엔진 Execution Engine

인터프리터 Interpreter

  • 바이트 코드를 한 줄 씩 실행

    JIT 컴파일러

  • 인터프리터 효율을 높이기 위해, 반복되는 코드를 발견하면 JIT 컴파일러가 반복되는 코드를 모두 네이티브 코드로 바꿔놓고, 다음에 중복 사용할 때 네이티브 코드로 이미 컴파일링 된 코드를 사용한다.
  • 프로그램 속도를 향상시키기 위함

    GC

  • 더 이상 참조되지 않는 객체를 모아서 정리한다.

JNI : Java Native Interface

  • 자바 어플리케이션에서 C, C++, 어셈블리로 작성된 함수를 사용할 수 있는 방법 제공
  • Native 키워드를 사용한 메소드 호출

Native Method Library

  • C, C++로 작성된 라이브러리
    reference

더 자바, 코드를 조작하는 다양한 방법
JVM에 관하여 - Part 3, Run-Time Data Area