기계어 코드
이다..java 파일을 작성하고 자바 컴파일러의 javac
명령어를 사용하여 텍스트 파일로 작성된 java 파일을
바이트 코드로 컴파일 합니다. 컴파일된 파일은 class
확장자를 가지며, JVM이 이해할 수 있는 형태로 저장됩니다.
바이트 코드의 각 명령어는 1바이트 크기의 Opcode와 추가 피연산자로 구성됩니다.
아래 이미지는 Main.java
파일을 javac
를 이용하여 컴파일한 후, 추출된 Main.class
파일의
바이트 코드를 보여줍니다.
1) 소스코드를 작성하여 저장 -> Main.java
2) javac를 이용한 컴파일
3) Main.class 파일의 바이트 코드
JVM의 클래스 로더는 컴파일된 바이트 코드를 메모리에 로드하고, 검증
, 준비
, 분석
, 초기화
과정을 통해 실행 준비를 완료합니다. 이 과정에서 필요한 클래스들(예: 사용자 정의 클래스, 라이브러리 클래스)을 동적 로딩을 통해 로드하고 링크하여 JVM의 런타임 데이터 영역에 올립니다.
로드: 클래스 파일을 가져와서 JVM의 메모리에 로드
검증: 자바 언어 명세(Java Language Specification) 및 JVM 명세에 맞게
구성되어 있는지 검사
준비: 클래스가 필요로 하는 메모리를 할당 (필드, 메서드, 인터페이스 등)
분석: 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경
초기화: 클래스 변수들(static 필드)을 적절한 값으로 초기화
실행엔진은 JVM 메모리에 올라온 바이트 코드들을 명령어 단위로 하나씩 가져와서
실행합니다. 이때, 두가지 방식으로 명령어를 처리합니다.
바이트 코드 명령어를 하나씩 읽어서 해석하고 실행합니다. 하나하나의 실행은 빠르나, 전체적인
실행 속도가 느리다는 단점을 가집니다.
인터프리터의 단점을 보완하기 위해 도입된 방식으로, 바이트 코드 전체를 컴파일하여 각 OS에 맞는
네이티브 코드로 변환한 후 해당 메서드를 네이티브 코드로 직접 실행합니다.
이는 인터프리터 방식보다 전체적인 실행 속도를 빠르게 합니다.
모든 코드를 JIT 컴파일러 방식으로 실행하지 않고, 인터프리터 방식을 사용하다 일정 사용기준을
넘어가면 JIT 컴파일러 방식으로 실행합니다. 또한 실행할 때 컴파일한 코드를 캐싱합니다.
JVM은 실행 중에 코드의 실행 패턴을 분석하여 최적의 성능을 발휘할 수 있도록 자동으로 최적화합니다.
개발자는 이러한 최적화 과정을 직접 제어할 필요가 없으며, JVM이 알아서 인터프리터와 JIT 컴파일러를 적절히 사용하여 최적의 성능을 보장합니다.
public class HelloWorld {
public static void main(String[] args) {
System.out.println("Hello World!");
}
}
이 간단한 프로그램은 System.out.println("Hello World!"); 한 줄만 실행하면 됩니다. 복잡한 계산이 없으므로 JIT 컴파일러가 개입할 필요가 없습니다.
프로그램은 인터프리터에 의해 한 줄씩 해석되고, 곧바로 "Hello, World!"를 출력합니다.
public class Calculation {
public static void main(String[] args) {
long sum = 0;
for (int i = 0; i < 10000; i++) {
sum += calculate(i);
}
System.out.println("Sum: " + sum);
}
public static int calculate(int number) {
return number * 2;
}
}
for
루프를 반복하면서 calculate
메서드를 호출합니다.calculate
메서드 호출은 인터프리터에 의해 해석되고 실행됩니다.calculate
메서드가 자주 호출된다는 것을 감지합니다.calculate
메서드를 네이티브 코드로 컴파일합니다.calculate
메서드는 인터프리팅 과정을 거치지 않고, 이미 컴파일된 네이티브 코드를 직접 실행합니다.이 최적화 덕분에 calculate
메서드의 실행 속도가 크게 향상됩니다.
추가) 네이티브 코드 예시
.section .rodata .LC0: .string "Hello, World!" .section .text .globl main .type main, @function main: pushq %rbp movq %rsp, %rbp leaq .LC0(%rip), %rdi call puts movl $0, %eax popq %rbp ret
ref.
https://ssocoit.tistory.com/270#1._JVM%EC%9D%B4%EB%9E%80?
[Java] 컴파일 과정