JVM Class Loader 동작 과정

주현·2025년 12월 1일

JAVA

목록 보기
10/12

Class Loader(클래스 로더)

클래스 로더는 자바 컴파일러가 변환해둔 ByteCode(.class)파일을 동적 로딩합니다.
실행 엔진이 사용할 수 있도록 JVM메모리에 적재하는 역할을 합니다. 로딩 -> 링크 -> 초기화 단계를 진행합니다.

✅ 로딩

.class 파일을 바탕으로 JVM(메서드 영역)에 로드합니다.
동적로딩을 하기 때문에, static변수나 사용하지 않는 클래스는 로드하지 않습니다. 즉, 한번에 메모리에 모두 로딩하는 게 아니라, 필요한 경우 동적으로 메모리에 로딩을 해주게됩니다.
메서드와 변수 & Class, Interface, Enum 을 구분해서 저장을합니다.
또한, Fully-Quailified Class Nmae형식으로 저장합니다. 로딩이 끝나면 해당 클래스 타입의 객체를 생성하여 메모리 Heap영역에 저장을 합니다.

동적로딩에 대해서 조금 더 알아보면,

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
    }
}

class Tests {

}

위 코드와 같이 .class 파일에 Temp라는 클래스가 있다고 하더라도, 해당 클래스를 사용하지 않는다면 로드를 하지않습니다. 사용시점에서 로드를 해주게 됩니다.
java -verbose:class test.java 명령어로 로드된 클래스를 확인해봤습니다.

보면, test클래스는 사용하므로 로드 되지만, Tests클래스는 사용하지 않고있기 떄문에 로드되지가 않습니다.

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
        
        Tests test = new Tests();
    }
}
class Tests {

}

반면 위 코드는 Tests 클래스를 사용했으므로 로드된 것을 확인할 수 있습니다.

그러나, 클래스를 명시적으로 선언(초기화)하지 않아도 로드되는 경우가 있는데, 클래스를 초기화 하지않고 클래스 내부에 static 변수를 호출할 때이다.

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
        String test = Tests.str;
    }
}
class Tests extends P{
    static String str = "hello";
}

class P{

}

Tests 클래스에 static String str의 static 변수가 있을때,Tests.str 라는 명령어를 만나게 되면, Tests 클래스도 같이 로드됩니다.

만약 Tests클래스가 P라는 클래스를 상속하고 있다면, 상속하는 P 클래스도 같이 로드됩니다.


위와 같이 test, P, Tests 클래스가 로드된 것을 확인할 수 있습니다.

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
        new Tests().new In();
    }
}
class Tests {
    class In{

    }
}

이런 식으로 내부 클래스를 상황에서도 내부 클래스를 갖는 외부 클래스를 로드합니다.

클래스 내 멤버를 사용하지만, 클래스를 로드하지 않는 경우도 있습니다.

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
        String str = Tests.str;
    }
}
class Tests {
    static final String str = "str";
}

static final String str라는 static final 변수가 있을 때, Tests.str 명령어를 실행하면 Tests 클래스는 로드되지 않습니다.

상수는 JVM의 Constatnt Pool에 따로 저장되어 관리되기 때문입니다.

public class test {

    public static void main(String[] args) {
        System.out.println("Main start");
        Tests.In str = new Tests.In();
    }
}
class Tests {
    static class In{

    }
}

혹은 static class In와 같은 내부 클래스가 있을때, new Tests.In();의 경우 인스턴스를 생성할 때, 외부 클래스가 꼭 필요하지 않으니 외부클래스인 Tests를 로드하지않습니다.


✅ 링크

링크는 클래스 파일을 사용하기 위해 검증하는 과정입니다.

  1. 검증 : 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 구성되어 있는지 검사합니다. 검증을 실패하면 런타임에러를 발생시킵니다.
    -> 검승된 컴파일러가 만든 class파일이 아닌 제 3자가 수동으로 변경한 경우에도 검증을 실패합니다. 따라서 악의적 변경을 방지합니다.
  2. 준비 : 클래스가 필요로 하는 메모리를 할당하고 클래스의 필드, 메서드, 인터페이스를 나타내는 데이터 구조를 준비합니다.
    -> 메모리를 할당하고 정적필드가 기본값으로 초기화됩니다.
  3. 분석 : 클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 실제 메모리 레퍼런스로 교체합니다.
    -> 심볼릭 레퍼런스 :메모리 번지가 아닌 이름에 의한 참조

✅ 초기화

링크 단계에서 확보한 메모리 영역에 클래스의 static 변수를 명시된 값으로 할당합니다.

0개의 댓글