1주 차 과제 : JVM 은 무엇이며, 자바 코드는 어떻게 실행하는 것인가.

JVM 이란 무엇인가

JVM (자바 가상 머신) 이란 Java와 Kotlin, Scala 등이 컴파일된 바이트코드를 실행하는 Virtual machine이다.

컴파일하는 방법 Java Compiler : wikipedia

Java Compiler 명령어를 사용하고 Source File의 Path를 넘겨주면 된다.

Directory\Study>Javac source.java  // File Path를 이용하여 컴파일한다. -> Directory\Study\source.java

바이트코드란 무엇인가? Bytecode : wikipedia

Java Bytecode 란 Java의 Execution Engine를 통해 수행될 수 있는 상태의 코드를 말한다. (기계어보다 추상적이다.)

1번의 컴파일 단계를 더 거침으로써, 작성한 코드를 JVM이 설치된 모든 기기에서 실행 가능하다. (JVM에 종속적)

실행하는 방법

>Java source  // source.class

자바 코드를 실행하기 위해선 .java 파일 (즉 SourceFile)를 컴파일하여 그 기기에 맞는 .class (Bytecode)로 변환해주어야 하며, 해당 파일을 인터프리터와 JIT 컴파일러를 통해 해석하여 프로그램을 실행하게 된다.

자바 프로그램의 기본적인 실행 절차.

  1. 해당 Java 파일을 Java Compiler가 Class 파일로 (Bytecode) 변환
  2. 클래스 로더가 JRE 환경을 조성한 후 Application 클래스 로더는 해당 클래스를 PATH를 이용해서 로드 (JVM 실행)
  3. 로드된 바이트 코드를 실행 엔진으로 넘기게 되고, 실행 엔진 내부의 인터프리터에서 내부 클래스를 행단위로 읽어 들인다.
  4. (Static Obj의 경우에는 실행 엔진 이전에 클래스 로더의 초기화 단계에서 생성, 그 외의 정보는 PERM으로)
  5. 인터프리터 내부의 Counter가 만족되면 JIT 컴파일러를 호출하여 실행하게 된다. (중복되는 코드는 캐싱된 코드를 사용한다.)
  6. Class 파일을 기계어로 컴파일하고 런타임 메모리에 올리게 된다.
  7. Main Method에 일정한(기본적으로 빈 배열 등) 인자 값을 넘기고 실행한다.
  8. Main Method 내부에서 필요한 객체가 있다면 해당 객체를 생성하기 위해 PERM Gen의 Class 정보를 읽는다.
  9. 리플렉션을 통해 클래스 이름을 가지고 타입을 특정하고 해당 클래스의 메서드, 변수, 생성자 등을 읽어서 생성한 뒤에 Heap 영역에 띄운다.
  10. 해당 객체를 지역 변수를 통해 참조하거나 다른 객체의 인스턴스 변수가 참조하여 사용한다.

JIT 컴파일러란 무엇이며, 어떻게 동작하는지

JIT 방식은 프로그램을 실행하는 동안 필요한 바이트코드를 기계어로 번역하는 기법을 말하며, JVM에선 해당 기법을 구현한 녀석을 JIT Compiler라고 한다.

JVM 구성 요소

Class Loader

  • Bootstrap Class Loader
    첫 번째로 동작하는 Class Loader이며, jre 실행 환경을 조성하는 등의 Java Library Class들을 로드하게 된다.
    Runtime, i18n Class... (Nativecode로 구성되어 있다.)

  • Extention Class Loader
    jdk/ jre 패키지 내부의 ext 디렉터리에 있는 Class들을 로드하게 된다.

  • Application Class Loader (System Class Loader)
    Class Path를 기반으로 실행할 Class를 로드하게 된다.

로드된 Class 들은 로딩 -> 링크 -> 초기화의 절차를 진행하게 된다.

링크, 초기화 이후에는 참조로 연결된 Class 들을 로드하는 절차가 추가될 수 있다.

 

Execution Engine

  • interpreter
    프로그램 실행을 위하여 Bytecode를 Nativecode로 변환하기 위해 행별로 해석하는 구현체.
    내부적으로 Counter를 지니고 있으며, 해당 행을 해석할 때마다 Counter의 수치가 증가한다.
    일정 수치를 만족하게 되면 JIT Compiler를 호출하여 Dynamic Loading, Compile을 수행하게끔 한다.

  • JIT Compiler
    interpreter의 요청에 따라 컴파일을 수행하는 구현체이다.
    성능 최적화를 위하여 코드를 캐싱하다가 중복 코드가 발견된다면 캐시 된 코드를 재사용한다

Runtime Data Areas

  • Permanent Generation
    Class, Interface, Package 등의 Meta 정보를 저장하고 String Pool 제외한 Constant Pool을 관리하는 공간이다.
    JDK 7 에선 String Pool 이 Heap으로 이동하였으며,
    JDK 8 에선 Static Object 이 Heap 으로 이동하고, OS Memory 상에서 위치하게 변경되었다.

  • Heap Area
    New로 생성되는 Instance 들과, Static Object, String Pool 이 관리되는 영역이다.
    GC를 통하여서 메모리 관리가 이루어지고, 다른 모든 영역에서 공유가 되는 영역이다.
    Young 영역, 2개의 Survivor 영역, Old 영역으로 이루어져 있다. (Hotspot JVM. JDK 8 기준)
    Young과 Survivor 영역에서 이루어지는 GC를 Minor GC라고 하고, Old 영역에서 이루어지는 것을 Major GC 라고 한다.
    JDK 9부터는 G1 GC라는 모듈이 Default로 설정되어 있으며, 영역별로 나누어져있지 않고 메모리 영역을 2천 개 이상의 작은 영역으로 분할하게 되어있다.

  • Stack Area
    Scope에 따른 크고 작은 Stack Frame과 지역 변수, 스레드 들의 Life Cycle이 진행되는 영역이다.
    Application이 실행되는 동안 Main Method Stack Frame 위에서 다른 Frame 이 생성되고 사라진다.
    스레드들은 각각의 Stack 공간(Runtime Stack)을 가지게 되고, 여러 자원을 공유할 수 있다. (가시성 문제가 발생할 수 있다.)

  • PC Register
    Thread 가 생성될 때 같이 생성되는 공간이다. Thread가 실행할 명령의 위치를 기록한다.

  • Native Method Stack
    자바 이외의 언어에서 제공되는 Method의 정보가 저장되는 공간이다.
    JNI(Native Method Interface)와 Library를 통해 표준에 가까운 방식으로 구현된다. (Thread Class 등)

JDK와 JRE의 차이

JRE : Java Runtime Environment
Java Application을 실행하기 위한 최소의 실행 환경을 제공하는 것.
JVM + Java API (핵심 라이브러리)가 포함되어 있다.

JDK : Java Development Kit
JRE에서 제공하는 실행 환경과 개발에 필요한 API, 명령어(메모리 확인, 배포 등), Compiler를 포함하고 있는 것.
JVM, Java API, Java Tool, Java Compiler 가 포함되어 있다.

< Reference >

https://ko.wikipedia.org/wiki/%EB%B0%94%EC%9D%B4%ED%8A%B8%EC%BD%94%EB%93%9C https://ko.wikipedia.org/wiki/%EC%BB%B4%ED%8C%8C%EC%9D%BC%EB%9F%AC
[JVM Performance Optimizing 및 성능 분석 사례]

+ Recent posts