이전 글인 (3) JVM을 읽고 오면 좋습니다.
클래스가 요청될 때 실행할 클래스 파일(.class 바이너리 파일)을 읽고 JVM 메모리에 올려놓는 작업을 처리한다.
세부적으로 로딩 - 링크 - 초기화 세단계로 나뉜다.
아니다. 자바는 실행에 필요한 모든 내용을 한 번에 메모리에 로딩하는 게 아니라 실제 클래스가 요청될 때 메모리에 로드한다.
public class Hello {
public static void main(String[] args){
System.out.println("Hello, world");
}
}
위와 같은 hello.java 파일이 있고 해당 파일을 컴파일 후 실행한다고 가정해보자.
그럼 Hello 클래스를 로드할 때 이 클래스가 참조하고 있는 Object, String, System 클래스가 아직 로드되지 않았으므로 Hello 클래스를 로드하는 일을 중단하고 이 클래스들을 로딩한다(Resolving).
이와 같이 한 클래스의 로드 타임에 필요한 다른 클래스들을 동적으로 로딩하는 것을 로드타임 동적 로딩이라고 한다.
또다른 예시를 보자.
// package com.example.test;
// loadingInterface.java
public interface LoadingInterface {
public void run();
}
// loadingClass1.java
public class LoadingClass1 implements LoadingInterface {
@Override
public void run() {
System.out.println("Loading1");
}
}
// loadingClass2.java
public class LoadingClass2 implements LoadingInterface {
@Override
public void run() {
System.out.println("Loading2");
}
}
위와 같이 정의된 인터페이스와 클래스가 있다.
// loading.java
public class RuntimeLoading {
public static void main(String[] args) {
try {
Class<?> cls = Class.forName(args[0]);
Object obj = cls.newInstance();
LoadingInterface loading = (LoadingInterface) obj;
loading.run();
} catch(Throwable e) {
e.printStackTrace();
}
}
}
위의 RuntimeLoading 파일을 실행하는 경우 아래와 같은 결과가 출력된다.
// 매개변수로 'com.example.text.LoadingClass1'을 넣은 경우
Loading1
// 매개변수로 'com.example.text.LoadingClass2'을 넣은 경우
Loading2
이 경우 LoadingClass1, LoadingClass2 클래스는 RuntimeLoading 파일을 실행하기 전에 미리 메모리에 올라와있지는 않으나, Class.forName() 메소드에 의해 런타임에 로드된다.
이렇게 컴파일 시에는 전혀 알지 못하는 클래스를 런타임에 로드하여 실행하는 경우를 런타임 동적 로딩이라고 한다.
(이미지 출처 : https://www.cs.rit.edu/~ark/lectures/cl/05_01_00.html)
클래스 로더는 계층 구조로 이루어져 있다.
위에서부터 차례대로 Bootstrap, Extension, System 클래스 로더가 있으며 그 아래에 System 클래스 로더를 확장해 만드는 User-Defined Class Loader가 있다.
클래스 로더는 위임 모델(Delegation Model)에 따라 동작한다.
1. 클래스 로딩을 요청받은 클래스 로더는 이전에 클래스를 로딩한 적이 있는지 확인한다.
2. 만약 로딩한 적이 없으면 상위 부모 클래스 로더에게 클래스 로딩 요청을 위임한다.
3. 클래스 로딩을 위임받은 부모 클래스 로더 또한 캐시를 먼저 확인하고 이전에 로딩한 적이 없다면 그 클래스 로더의 부모에게 클래스 로딩을 위임한다.
4. 최상위 부트스트랩 클래스 로더까지 요청이 위임되고 이전에 클래스라 로딩된 적이 없다면 최상위 부모부터 자식 클래스 로더 순서로 클래스 로딩을 시도한다.
5. 만약 클래스 로딩에 실패하면 ClassNotFoundException을 발생한다.