JVM의 인터프리팅과 클래스로딩 Optimizing Java #2

BaekGwa·2024년 8월 8일

Optimizing Java

목록 보기
2/5
post-thumbnail

이글은, 오라일리 사의 Optimizing Java 책을 참고하여, 정리한 내용이다.

도입

JVM 이란?

  • JVM은 Java 프로그램의 플랫폼 독립성을 제공하고, 다양한 하드웨어와 운영체제에서 프로그램을 실행할 수 있도록 하는 가상 머신입니다. JVM은 바이트코드 실행, 메모리 관리, 보안, 다양한 언어 지원 등 많은 중요한 기능을 제공 합니다.
  • JVM이 없는 C/C++로 작성된 프로그램은 운영체제나 하드웨어가 달라지면 실행할 수 없는 경우가 많습니다. 반면, Java는 동일한 버전의 JVM이 해당 운영체제에 맞게 설치되어 있다면, 플랫폼에 관계없이 동일하게 실행할 수 있습니다.

JVM 이야기

인터프리팅과 클래스 로딩

인터프리팅 : 소스 코드나 중간 코드를 직접 실행하는 방식입니다. 인터프리터는 프로그램의 명령어를 한 줄씩 읽고 실행합니다. 이 과정에서 소스 코드나 바이트코드를 직접 해석하고 수행하는 역할을 합니다.

클래스 로딩 : JVM에서 클래스 파일을 읽어들여 메모리에 로드하는 과정을 말합니다. 이 과정은 JVM의 클래스 로더에 의해 수행되며, 클래스의 바이트코드를 메모리에 적재하고, 클래스의 정의를 관리하여 프로그램 실행 중 사용할 수 있도록 합니다.

  • JVM은 스택 기반의 해석 머신 입니다. 레지스터는 없지만, 일부 결과를 실행 스택에 보관하며, 이 스택의 맨 위에 쌓인 값들을 가져와 계산을 진행합니다.

  • JVM 인터프리터(해석기)는, 평가 스택을 이용해 중간 값들을 담아두고 가장 마지막에 실행된 명령어와 독립적으로 프로그램을 구성하는 옵코드(Operation Code)를 하나씩 순서대로 처리하는 While 루프 안의 Switch문 입니다.

  • HelloWorld 라는 아주 간단한, Java 코드를 실행한다고 가정합니다. 자바 애플리케이션을 실행하면, 다음과 같은 순서를 가질 것입니다.

    1. 가상 머신 프로세스(자바 바이너리 구동)
      • java HelloWorld // 명령어 실행
    2. 자바 가상 환경 구성되고, 스택 머신이 초기화
    3. 유저가 작성한 helloWorld 클래스 파일 실행.
  • 이때, 애플리케이션의 진입점은 HelloWorld.class에 있는 main() 메서드 이다. 제어권을 이 클래스로 넘거야 main 로직이 실행 될 수 있다.

  • 따라서 이 helloWorld 클래스를 로딩 시킬 필요가 있습니다.

Java는 동적 로드, 즉 컴파일 타임이 아니라 런타임(바이트 코드를 실행할 때)에 클래스를 링크하고 로드하는 특징이 있습니다.

  • 이때 자바 클래스 로딩(classloading) 메커니즘이 관여 합니다. 자바 클래스로더에는 3가지가 있습니다.

    1. 부트스트랩 클래스 로더
    2. 확장 클래스 로더
    3. 애플리케이션 클래스로더
  • 먼저 부트스트랩 클래스 로더 부터 실행되게 됩니다.

부트스트랩 클래스 로더

  • 가장 먼저 실행되는 클래스 로더로, 자바 런타임 코어 클래스를 로드 합니다.
  • 주임무는, 다른 클래스 로더가 나머지 시스템에 필요한 클래스를 로드 할 수 있게 최소한의 필수 클래스를 로드하는 역할입니다.
    • 예) java.lang.Object, Class, ClassLoader
  • 다음으로는 확장 클래스 로더가 실행됩니다.

확장 클래스 로더

  • 이 클래스로더는 주로 자바의 표준 라이브러리와 확장 라이브러리를 로드합니다.

애플리케이션 클래스 로더

  • 확장 클래스 로더까지 완료 되었다면, 지정된 클래스 패스에 있는 유저 클래스를 로드합니다.
  • 즉, 우리가 만든 .class 확장자 파일을 로드 합니다.

완료 후,

  • 애플리케이션 클래스 로더까지 완료되었다면, 제어권을 main() 에 전달하며 애플리케이션이 실행 됩니다.

간단한 클래스 로더 실행 순서 예제

  • 다음과 같은 main class가 있습니다.
public class Main {
    public static void main(String[] args) {
        System.out.println("Starting main method");

        // 10초 동안 대기
        try {
            Thread.sleep(10000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        // Test 클래스 사용
        Test test = new Test();  // 이 시점에서 Test 클래스가 로드됩니다.
        test.sayHello();
    }
}

class Test {
    public void sayHello() {
        System.out.println("Hello from Test class!");
    }
}
  • 이 코드로 이뤄진 Application을 실행하게 되면 다음과 같은 순서를 가지게 됩니다.
    컴파일은 완료 되었다고 생각합니다.

    초기화단계

    1. java Main //명령어 실행
    2. 자바 가상 환경 구성되고, 스택 머신이 초기화

    실행단계

    1. 진입점인, Main() 클래스를 실행하기 위해 Method Area에 클래스가 로드 되어있는지 확인.
    2. 로드 되어있지 않아, 애플리케이션 클래스로더에 Main 클래스 로드 요청
    3. 애플리케이션 클래스로더 -> 부트스트랩 클래스로더에 요청 위임.
    4. 부트스트랩 클래스로더에서 클래스 확인.
    5. 클래스가 없으므로, 애플리케이션 클래스로더로 요청 전달
    6. 애플리케이션 클래스로더에서 요청 접수 및 로딩
    7. main() 메서드가 실행되며, Sleep() 까지 진행 완료.
    8. Test 클래스 실행하기 위해 Method Area에 클래스가 로드 되어있는지 확인.
    9. 4~7단계 반복하여 Application 실행

이때, 8번 과정에서 애플리케이션 클래스로더가 클래스를 확인 하지 못한다면 ClassNotFoundException을 발생시킨다.

3번 과정에서 Method Area에 클래스가 로드되어있다면, 해당 클래스를 사용한다.

profile
현재 블로그 이전 중입니다. https://blog.baekgwa.site/

0개의 댓글