Post

[스터디 할래] week01. JVM은 무엇이며 자바 코드는 어떻게 실행하는 것인가

백기선님의 스터디 “스터디 할래”를 참고로 한 정리입니다.

JVM이란 무엇이며 자바 코드는 어떻게 실행하는 것인가

학습할 것

  • JVM이란 무엇인가
  • 컴파일 하는 방법
  • 실행하는 방법
  • 바이트코드란 무엇인가
  • JIT 컴파일러란 무엇이며 어떻게 동작하는지
  • JVM 구성 요소
  • JDK와 JRE의 차이

JVM이란 무엇인가

JVM이란 JAVA Virtual Machine(자바 가상 머신)의 약칭으로 JAVA의 바이트코드를 OS에 맞게 해석 해주는 역할을 한다.

- JVM이 나오게 된 배경

C/C++는 컴파일 플랫폼과 타켓 플랫폼이 다를 경우 프로그램이 동작하지 않는다. (환경, 플랫폼 = 운영체제 + CPU 아키텍처)

즉 동일한 플랫폼에서 컴파일과 실행을 같이 한다면 프로그램은 아무 문제 없이 동작하지만 플랫폼이 달라질 경우 타겟 플랫폼에서 프로그램이 동작하지 않는다.

-> 이로 인해 크로스 컴파일을 통해 각각의 실행하고자 하는 운영체제에 맞는 프로그램을 만들어야 했다. (크로스 컴파일 : 타겟 플랫폼에 맞춰 컴파일 하는 것)


java compile

출처 : oracle docs

이러한 불편함을 해소하기 위해 자바 컴파일러를 통해 자바 소스코드(java 파일)를 바이트 코드(class 파일)로 변환하고 바이트코드는 기계어가 아니기 때문에 os에서 실행시키기 위해 바이트 코드를 기계어로 번역해주는 과정을 한 번 더 거치는 JVM이 나오게 되었다.

즉 자바 바이트 코드는 타겟 플랫폼에 상관없이 JVM 위에서 동작하고 JVM은 타겟 플랫폼에 의존한다.


컴파일 하는 방법

cmd에서 자바 컴파일

Java Complier에 의해 .java 파일을 .class 파일 즉 자바 바이트 코드로 만들어보자.

Java Complier는 JDK를 설치하면 bin 디렉터리의 javac.exe로 존재한다. javac 명령어를 통해 .class 파일을 생성할 수 있다.

1
2
3
4
5
public class test {
    public static void main(String[] args) {
        System.out.println("Hello World");
    }
}

“Hello World”를 출력하는 .java 파일을 생성하고 파일이 있는 디렉터리에서 javac { java 파일 명 } 을 통해 컴파일한다.

1
C:\Users\user>javac test.java

현재 위치에 .class 파일이 생성되는 것을 확인할 수 있다.

자바 컴파일 과정

보통 IDE나 terminal 환경에서 .java파일을 생성하게 되는데 이 때 build를 통해 .class 파일을 생성하게 된다. 이는 아직 컴퓨터가 읽을 수 없는 자바 바이트코드이다.


실행하는 방법

위에서 만든 class 파일을 이용하여 java 명령어를 통해 실행시킬 수 있다.

java 명령어로 JDK의 bin 디렉터리에 java.exe를 실행시켜 JVM을 구동할 수 있다.

1
2
C:\Users\user>java test
Hello World

“Hello World”가 출력되면서 test.class 파일이 실행된걸 확인할 수 있다.


바이트코드란 무엇인가

바이트코드는 특정 하드웨어가 아닌 가상 컴퓨터(VM)에서 돌아가는 실행 프로그램을 위한 이진 표현법이다.

JVM이 이해할 수 있는 언어로 변환된 자바 소스코드를 의미한다. 자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 1byte라서 자바 바이트코드라고 불린다.

바이트코드는 다시 실시간 번역기 혹은 JIT 컴파일러에 의해 바이너리 코드(컴퓨터가 인식할 수 있는 0과 1로 구성된 이진코드)로 변환된다.


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

JIT 컴파일러

출처 : https://miro.medium.com/max/1400/1*VFo0CC-chzvqJk6sls6ukQ.png

JIT 컴파일 (Just In Time Compliation) 혹은 동적 번역(Dynamic Translation)이라고한다.

JIT 컴파일러는 프로그램을 실제 실행하는 시점에 바이트코드를 컴퓨터 프로세서(CPU)로 직접 보낼 수 있는 기계어로 번역하는 컴파일러이다.

전통적인 입장에서 컴퓨터 프로그램을 만드는 방법은 두가지로 인터프리터 방식과 정적 컴파일 방식으로 나뉜다.

  • 인터프리터 방식 : 실행 중 프로그램 언어를 읽어가며 해당 기능에 대응하는 기계어 코드 실행. 자바 바이트코드를 한줄씩 실행하여 여러번 실행하는 환경에서는 다소 느리다.
  • 정적 컴파일러 : 실행하기 전 프로그램 코드를 기계어로 번역

JIT 컴파일러는 인터프리터 방식의 단점을 보완하기 위해 도입되었다. 두가지의 방식을 혼합한 방식으로 생각할 수 있는데 인터프리터 방식으로 기계어 코드를 생성하면서 실행하다가 그 코드를 캐싱하여, 같은 함수가 여러번 불릴 때 매번 기계어 코드를 생성하는 것을 방지한다.

즉 같은 코드를 매번 해석하지 않고 실행할 때 컴파일하며 해당 코드를 캐싱한다. 이후에는 바뀐 부분만 컴파일하고 나머지는 캐싱된 코드를 사용하여 인터프리터의 속도를 개선할 수 있다.


JVM 구성 요소

JVM 구성 요소

출처 : https://namu.wiki/w/%EC%9E%90%EB%B0%94%20%EA%B0%80%EC%83%81%20%EB%A8%B8%EC%8B%A0

JVM의 구성요소는 크게 3가지로 나눌 수 있다.

구성 요소설명
Class Loader클래스를 Runtime Data Area에 적재한다.
Runtime Data Area런타임에 필요한 메모리 영역
Execution Engine메서드를 실행하는 실행 엔진


Class Loader

  • 런타임 시점에 클래스를 로딩한다. 인스턴스가 생성이 되면 Class Loader를 통해 메모리에 적재된다.
  • 세부적으로는 크게 Loading (클래스 파일 탑재), Linking (클래스 파일을 사용하기 위해 검증하고, 기본 값으로 초기화), 그리고 Initialization (static field 의 값들을 정의한 값으로 초기화) 과정을 거쳐 클래스 파일을 로딩한다.

Loading (클래스 파일 탑재)

  • 각각의 클래스 파일들이 기본으로 제공받는 클래스 파일인지 혹은 개발자가 정의한 클래스 파일인지와 같은 기준에 의해서 ClassLoader 의 수준도 세 가지로 나뉜다.

    ClassLoader

  • bootstrap class loader : 가장 먼저 실행되는 클래스 로더이다. 자바 실행에 기본적으로 필요한 클래스 즉 rt.jar 를 포함하여, JVM 을 구동시키기 위한 가장 필수적인 라이브러리의 클래스들을 로딩한다.
  • extension class loader : localedata, zipfs 등 다른 표준 핵심 Java Class 의 라이브러리 들을 로딩한다.(클래스들은 폴더 $JAVAHOME/jre/lib/ext_ 위치해 있다.)
  • application class loader : Classpath 에 있는 클래스를 로딩한다. classpath나 jar파일 내에 환경변수로 지정된 폴더 내 클래스를 로딩한다. (여기에 개발자들이 자바 코드로 짠 클래스 파일이 포함된다.)

위의 각각의 ClassLoader 들을 모두 거쳤는데도, 클래스 파일을 찾지 못하게 되면, ClassNotFoundException 이라는 예외를 던진다.

Linking (클래스 파일을 사용하기 위해 검증하고, 기본 값으로 초기화)

  • verification, preparation, resolution 단계로 이루어져있다.

  • verification : 읽어들인 바이트코드가 적절한지 확인한다. 실패시 java.lang.verifyError를 리턴
  • preparation : static 변수들에 메모리가 할당되고 타입에 따라 기본값을 할당한다.
  • resolution : 클래스의 constant pool 내의 모든 symbolic reference를 JVM 의 메모리 구성 요소인 Method Arearuntime constant pool을 통하여 Direct Reference 라는 메모리 주소 값으로 바꾼다. (해당 단계의 영향을 받는 JVM Instruction 요소는 new 및 instanceof 가 있다.)

Initialization (static field 의 값들을 정의한 값으로 초기화)

  • Java 코드에서의 class 와 interface 의 static 변수 값들을 지정한 값들로 초기화 및 static block이 실행된다.

Runtime Data Area

  • JVM이 바이트코드를 실행하기 위해 사용하는 (OS로부터 별도로 할당 받은) 메모리 공간이다.
  • JVM 의 Runtime Data Areas 에는 크게 Method Area, Heap, Java Stacks, PC registers 그리고 Native Method Stacks로 나뉜다.

    Runtime Data Areas

모든 스레드가 공유

Method Area

  • 클래스로더가 클래스 파일을 읽어왔을 때 클래스와 관련된 메타데이터를 저장하고 클래스 구조, 필드, 메서드와 같은 데이터를 저장한다.
  • Runtime Constant Pool 과 static 변수, 그리고 메소드 데이터와 같은 Class 데이터가 관리되는 곳이다.

Heap

  • 런타임시, 동적으로 할당하여 사용하는 영역이다. 프로그램을 실행하면서 생성한 모든 객체 인스턴스를 저장한다.
  • 여기서 문자열에 대한 정보를 가진 String Constant Pool과 실제 데이터를 가진 인스턴스, 배열 등이 저장된다.

각각의 스레드에 존재

Stack

  • 자바 스택은 스레드 별로 존재하고 각 Thread 들은 메서드를 호출할 때마다 Frame 이라는 단위가 생성된다.
  • 메서드 실행이 끝나면 스택 프레임은 pop되어 스택에서 제거된다.
  • Frame 은 메서드에 대한 정보를 가지고 있는 Local Variable, Operand Stack 그리고 Constant Pool Reference 로 구성이 되어 있다.
    • Local Variable : 메서드 안의 지역 변수를 가지고 있다.
    • Operand Stack : 메서드 내 연산을 위해서 바이트 코드 명령문을 가지고 있다.
    • Constant Pool Reference : Constant Pool 참조를 위한 공간이다.

Program Counter Register

  • 현재 실행 중인 JVM 주소 정보를 저장한다.
  • 수행해야 하는 CPU 명령어 위치 정보를 저장한다.

Native Method Stack

  • 자바의 바이트코드가 아닌 다른 언어로 작성된 메서드를 성능 향상을 목적으로 컴파일해서 사용하는 경우 사용된다.

Execution Engine

  • 로드된 class의 바이트코드를 실행하는 runtime module이다. class loader를 통해 jvm 내의 Runtime Data Area에 배치된 바이트코드는 Excution Engine에 의해 실행된다.

Garbage Collector

  • Heap 메모리 영역에 생성된 객체들 중 참조되지 않은 객체들을 제거 한다. System.gc()를 호출하여 실행할 수 있다. GC 동작시간은 정해져있지 않으므로 언제 제거하는지는 알 수 없다. GC를 수행하는 동안 GC Thread를 제외한 다른 모든 Thread는 일시 정지한다.

    Interpreter

    JIT compiler


JDK와 JRE의 차이

  • JDK(Java Development Kit) 자바 애플리케이션의 개발 환경이다. 자바를 사용하귀 위해 필요한 기능을 갖춘 자바용 SDK이다. JDK를 이용해 프로그램을 생성, 실행, 컴파일 할 수 있다.
  • JRE(Java Runtime Environment) JVM + 자바 클래스 라이브러리(Java Class Library) 등으로 구성되어 있다.

즉 JDK는 자바 프로그램을 실행, 컴파일, 개발용 도구이며 JRE, JVM를 모두 포함하는 포괄적이 키트이다. JRE는 자바 프로그램을 실행할 수 있게 하는 도구이다. JVM을 포함하고 있다.

자바9부터 JRE가 사라지는 이유는 사실 JDK가 JRE에 다 들어있기 때문이다.

This post is licensed under CC BY 4.0 by the author.