[Java] JDK, JRE and JVM

NHJ·2021년 12월 28일
0

JVM이란?

JVM은 Java Virtual Machine의 약자로 직역하면 자바 가상 머신이다. 가상 머신이란 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것이다. JVM은 자바 바이트코드를 클래스 로더를 통해 읽어 자바 API와 함께 실행시킨다. JVM은 JAVA와 OS사이에서 중개자 역할을 수행하여 JAVA가 OS에 구애받지 않고 재사용을 가능하게 해준다. 또한 가비지 컬렉터를 사용한 메모리 관리도 자동으로 수행하며 ARM 아키텍쳐 같은 레지스터 기반 하드웨어와는 다르게 스택 기반으로 동작한다.

자바프로그램 실행 과정

  1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다.
    JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다
  1. 자바 컴파일러(javac)가 자바 소스코드(.java)을 읽어들여 자바 바이트코드(.class)로 변환시킨다.

  2. Class Loader를 통해 class파일들을 JVM으로 로딩한다.

  3. 로딩된 class파일들은 Execution engine을 통해 해석된다.

  4. 해석된 바이트코드는 Runtime Data Area에 배치되어 실질적인 수행이 이루어진다.


JVM 구조

1. Class Loader

Class Loader는 class 파일을 로드하는데 사용되는 하위 시스템으로 Class Loading, linking, initialization을 통해 작업을 수행한다. Runtime시에 동적으로 class를 로드하며 jar파일 내 저장된 class들을 JVM위에 탑재하고 사용하지 않는 class들은 메모리에서 삭제한다. 자바는 컴파일 타임이 아니라 런타임에 참조한다. 즉 클래스를 처음으로 참조할때 해당 클래스를 로드하고 링크한다.

  • Loading

    • JVM은 Bootstrap, extension, applicaion 3가지의 class loader을 가진다.
    • 첫째로 bootstrap class loader가 JRE lib 폴더에서 rt.jar 파일을 탐색한다.
    • class를 찾지 못하면 extension class loader가 jre/lib/ext 폴더를 탐색한다.
    • class를 찾지 못하면 application class loader가 시스템 환경 변수 CLASSPATH에 있는 모든 jar 파일들과 class들을 탐색한다.
    • 위 과정에서 class를 찾는다면 로드되고 찾지 못한다면 ClassNotFoundException이 발생한다.
  • Linking
    class가 로드되면 linking이 수행된다. bytecode verifier는 생성된 바이트코드가 적절한지 검증하며 실패시 에러를 발생시킨다. 이로 인해 프로그램의 접근을 제한하고 시스템 외부에 비정상적인 영향을 끼치는 것을 방지 할 수 있어 Java의 보안성을 높이는 역할을 한다. 주요 검증 내용은 다음과 같다.

        1) Code가 JVM이 명시한 내용과 일치 한지
        2) Memory에 허가 되지 않은 접근이 존재 하는지
        3) Stack Over Flow 체크
        4) Data Types 체크

  • Initialization
    - class loading의 마지막 단계이며 코드의 위에서부터 아래로 모든 정적 변수의 값이 할당되며 static block이 실행된다.

  public class StaticTest {   
     public static int X = 10;   
     public static void main (String [] args) {       
        System.out.println (Y);//Output 60   
     }   
     static {       
        X = 30;   
     }  
     public static int Y = X * 2;
  }

위의 코드에서 X는 10으로 초기화되고 30으로 할당된 뒤 Y는 60으로 초기화될 것이다.

2. JVM Execution Engine

클래스 로더가 JVM내의 메모리 영역에 바이트 코드를 배치시키면 Execution Engine에 의해 실행된다. 자바 바이트코드는 기계가 바로 수행하는 언어보다는 비교적 인간이 보기 편한 형대로 기술된 것이다. 그래서 실행 엔진은 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경한다. 이때 두 가지 방식을 사용한다.

  • Interpreter
    Interpreter는 각 바이트코드 명령어를 상응하는 네이티브 명령어로 변환한다. 바이트코드를 직접 실행하며 최적화는 하지 않고 느리다는 단점이 있다.
  • JIT(Just In Time)
    Interpreter 방식의 성능을 향상시키기 위해 JIT 컴파일러가 도입되었다. Interpreter 방식으로 기계어 코드를 실행하면서 적절한 바이트코드 블럭을 컴파일하여 네이티브 코드로 변경하고 이후에는 인터프리팅 하지 않고 네이티브 코드로 직접 실행하는 방식이다. 네이티브 코드는 캐시에 보관하기 때문에 한번 컴파일된 코드는 빠르게 수행하게 된다. 하지만 모든 코드를 컴파일하면 프로그램 시작 시간에 크게 영향을 줄 수 있다. 따라서 JVM은 내부적으로 해당 메소드가 얼마나 자주 수행되는지 확인하고 일정 정도를 넘을때에만 컴파일을 수행한다.

  • Garbage Collector
    동적 할당된 메모리 영역 가운데 더 이상 사용할 수 없게 된 영역을 탐지하여 자동으로 해제한다.

3. Runtime Data Area

프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간이다. Method와 Heap영역은 모든 Thread가 공유하며 PC Register, Stack, Native Method stack는 공유되지 않고 Thread마다 독립적으로 가진다.

  • PC Register
    PC Register는 현재 Thread가 실행되고 있는 부분의 물리적 주소를 저장하고 있다.

  • JVM stack
    프로그램 실행과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다. 지역변수, 리턴값 매개변수등이 이에 해당한다.

  • Native Method stack
    자바 언어 이외의 언어로 작성된 코드를 저장하는 메모리 영역이다. C나 C++같은 언어가 이에 해당한다.

  • Method Area (= Class Area = Static Area)
    class 정보를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이다. class의 metadata, 메소드 code등이 저장된다. 이 공간에는 Runtime Constant Pool이라는 별도의 관리 영역도 존재하는데 이는 상수 자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.

    올라가는 정보의 종류

    1) Field Information
    멤버 변수의 이름, 데이터 타입, 접근 제어자에 대한 정보
    2) Method Information
    메소드의 이름, 리턴타입, 매개변수, 접근제어자에 대한 정보
    3) Type Information
    class인지 interface인지의 여부,Type의 속성, 전체 이름, super class의 전체 이름(interface 이거나 object인 경우 제외)

  • Heap

    객체를 저장하는 가상 메모리 공간이다. new 연산자로 생성된 객체와 배열을 저장한다. Heap 영역이 가득차면 OutOfMemoryError가 발생한다.

    • Young Generation
      Eden 영역은 Object(객체)가 최초로 Heap에 할당되는 장소이다. 만일 Eden 영역이 가득 찼다면, Object의 참조 여부를 파악하고 Live Object는 객체가 있는 Suvrvior 영역으로 넘긴다. 그리고 참조가 사라진 Garbage Object이면 남겨 놓는다. 그리고 모든 Live Object가 Survivor 영역으로 넘어간다면 Eden 영역을 모두 청소한다.

      Survivor 영역은 Survivor0과 Survivor1로 구성되며 Eden 영역에 살아 남은 Object들이 잠시 머무르는 곳이며 Live Object들은 하나의 Survivor 영역만 사용하게 되며 이러한 전반적인 과정을 Minor GC라고 한다.

    • Old(Tenured) Generation
      Old Generation은 새로 Heap에 할당된 Object가 들어오는 것이 아닌, Survivor 영역에서 살아남아 오랫동안 참조 되었고 앞으로도 사용될 확률이 높은 Object들을 저장하는 영역이다. 이러한 Promotion 과정 중 Old Generation의 메모리가 충분하지 않으면 해당 영역에서 GC가 발생하는데 이를 Major GC라고 한다.(Tenured 영역에서 발행한 GC)

JRE란?

Java Runtime Environment의 약자로 JVM 에서 실행하기 위한 자바 애플리케이션을 실행할 수 있도록 구성된 배포판을 의미한다. JRE는 자바 개발 키트를 다운로드할 때 기본적으로 포함되며 각 JRE 에는 코어 자바 클래스 라이브러리, 자바 가상 머신이 포함된다.

JDK란?

Java Development Kit의 약자로 JRE가 가지고 있는 모든것과 Java 응용프로그램을 개발, 디버깅 및 모니터링하기 위한 개발도구를 포함하고 있다. 자바 애플리케이션을 개발해야 할 때 JDK가 필요하다.

JDK, JRE, JVM의 차이

JDK, JRE, JVM은 위의 그림과 같은 관계를 가진다.

JRE = JVM + 자바 애플리케이션 코어 라이브러리
JDK = JRE + 자바 애플리케이션 개발 도구


[참고]

profile
화이팅!

0개의 댓글