이미지 출처 : https://www.techcrashcourse.com/2017/02/difference-between-jdk-jre-and-jvm.html
이미지 출처 : https://honbabzone.com/java/java-jvm/
위의 그림과 같이 JVM은 3가지 서브 시스템으로 구분할 수 있다.
1) 부트스트랩 클래스 로더(Bootstrap Class Loader)
2) 익스텐션 클래스 로더(Extension Class Loader)
3) 애플리케이션 클래스 로더(Application Class Loader)
4) 커스텀 클래스 로더(Custom Class Loaders)
1) 인터프리터 (Interpreter)
1) JIT 컴파일러 (Just-In-Time Compiler)
2) AOT 컴파일러 (Ahead-of-Time Compiler)
1) 자바소스를 컴파일하여 .class 를 생성한다.
// 예제 자바 소스
public class Main {
public static void main(String[] args) {
System.out.println("Hello and welcome!");
}
}
2) 생성한 .class 의 위치에서 javap(역어셈블) 커맨드를 사용.
3) 출력된 Bite Code 확인
// Main.class의 Bite Code
public class Main
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#15 // java/lang/Object."<init>":()V
#2 = Fieldref #16.#17 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #18 // Hello and welcome!
#4 = Methodref #19.#20 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #21 // Main
#6 = Class #22 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 SourceFile
#14 = Utf8 Main.java
#15 = NameAndType #7:#8 // "<init>":()V
#16 = Class #23 // java/lang/System
#17 = NameAndType #24:#25 // out:Ljava/io/PrintStream;
#18 = Utf8 Hello and welcome!
#19 = Class #26 // java/io/PrintStream
#20 = NameAndType #27:#28 // println:(Ljava/lang/String;)V
#21 = Utf8 Main
#22 = Utf8 java/lang/Object
#23 = Utf8 java/lang/System
#24 = Utf8 out
#25 = Utf8 Ljava/io/PrintStream;
#26 = Utf8 java/io/PrintStream
#27 = Utf8 println
#28 = Utf8 (Ljava/lang/String;)V
{
public Main();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello and welcome!
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
}
SourceFile: "Main.java"
소스 코드 작성 :
".java" 확장자를 가진 자바 소스 코드를 작성
컴파일러 실행 :
작성한 소스 코드를 컴파일하기 위해 자바 컴파일러(javac)를 실행
컴파일러는 소스 코드를 읽어들이고 문법적으로 올바른지 검사한 후에 중간 형태인 바이트 코드로
변환하며 문제가 있다면 컴파일 오류가 발생함
바이트 코드 생성 :
컴파일러가 소스 코드를 분석하여 중간 언어인 바이트 코드로 변환
이 바이트 코드는 JVM이 이해하고 실행할 수 있는 형식
바이트 코드 파일 생성 :
컴파일러가 생성한 바이트 코드는 .class라는 확장자를 가진 파일에 저장됨
이 파일은 클래스 단위로 생성되며, 하나의 자바 소스 파일에 여러 개의 클래스가 있다면
각 클래스마다 별도의 .class 파일이 생성
바이트 코드 실행 :
생성된 바이트 코드는 JVM에서 실행됨
JVM은 플랫폼에 종속되지 않는 가상 머신으로, 바이트 코드를 실행하면서
자바 프로그램이 실제로 동작
// 예제 자바 소스
public class Main {
public static void main(String[] args) {
System.out.println("Hello and welcome!");
}
}
1) 컴파일 할 자바 소스가 있는 위치로 이동한다.
2) javac 파일명.java 명령어를 입력하여 컴파일한다.
3) 컴파일 된 .class 파일 확인
4) .class 파일 실행