JVM의 Class Loader는 자바 컴파일러에 의해 컴파일된 파일(.class)을 JVM으로 로드하여 런타임 메모리영역에 올리는 역할을 한다.
JVM의 Class Loader는 로딩 -> 링크 -> 초기화 순으로 진행된다.
각 단계에서 하는 일은 다음과 같다.
Loading은 Class Loader가 .class파일을 읽고 그 내용에 따라 적절한 Binary Data를 만든 뒤 Runtime Data Area의 Method Area에 저장하는 작업이다.
Class Loader의 두번째 작업인 Linking은 세 단계로 이루어진다.
아래 코드에서 foo라는 참조변수가 Heap에 저장된 실제 Foo 인스턴스를 가리킬 수 있도록 연결하는 작업이 Resolve 단계에서 일어난다.
Foo foo = new Foo();
Linking의 Prepare단계에서 확보한 메모리 영역에 클래스에서 static으로 선언된 변수와 메소드의 값들을 할당하고 초기값을 채운다.
static final String bar = "bar";
예를 들어 위의 코드를 보면 "bar"라는 문자열을 Prepare단계에서 준비한 메모리영역에 할당하고, 메모리의 레퍼런스를 변수 bar 에 연결하는 일련의 과정이 Initialization단계에서 일어난다.
Class Loader는 기본적으로 제공되는 클래스인지 사용자가 정의한 클래스파일인지에 따라 세 가지 수준으로 나뉜다.
Bootstrap ClassLoader
Extention ClassLoader
Application ClassLoader (System ClassLoader)
- JVM Method Area에 클래스가 로드되어 있는지 확인한다. 만약 로드되어 있는 경우 해당 클래스를 사용한다.
- JVM Method Area에 클래스가 로드되어있지 않는 경우, Application ClassLoader에 클래스 로드를 요청한다.
- Application ClassLoader는 Extention ClassLoader에 요청을 위임하고, Extention ClassLoader는 Bootstrap ClassLoader에 요청을 위임한다.
- Bootstrap ClassLoader는 Bootstrap CLASSPATH(jdk/jre/lib)에 해당 클래스가 있는지 확인하고, 클래스가 없을 경우 Extention ClassLoader에게 요청을 넘긴다.
- Extention ClassLoader는 Extention CLASSPATH(jdk/jre/lib/ext)에 해당 클래스가 있는지 확인하고, 클래스가 없을 경우 Application ClassLoader에게 요청을 넘긴다.
- Application ClassLoader는 Application CLASSPATH에 해당 클래스가 있는지 확인하고, 클래스가 존재하지 않는 경우 ClassNotFoundException 을 발생시킨다.
정리하자면 JVM의 Method Area에 클래스가 없는 경우 ClassLoader로 요청을 보내고 최상위 ClassLoader까지 요청을 위임한 뒤 최상위 ClassLoader부터 필요한 클래스를 찾아 내려오고, Application ClassLoader에서도 클래스를 찾지 못하는 경우 예외를 던진다.
Unique Classes
Hierarchy(계층 구조)
Can not Unload Classes(클래스 언로드 불가)
자바의 클래스 로딩은 클래스가 참조되는 시점에 JVM에 코드가 링크되고, 실제 런타임시점에 로딩되는 동적 로딩을 거친다. 즉, JVM은 미리 모든 클래스에 대한 정보를 Method Area에 로딩하지 않고 필요할 때 클래스로더에게 클래스로딩을 요청하여 Method Area에 올림으로써 효율적으로 메모리를 관리한다.
하나의 클래스를 로딩하는 과정에서 동적으로 다른 클래스를 로딩하는 것
Example Code
public class HelloWorld {
public static void main(String[] args) {
System.out.println("안녕하세요!");
}
}
클래스를 로딩할 때가 아닌, 코드를 실행하는 순간에 클래스를 로딩하는 것
Example Code
public class RuntimeLoading {
public static void main(String[] args) {
try {
Class cls = Class.forName(args[0]);
Object obj = cls.newInstance();
Runnable r = (Runnable) obj;
r.run();
} catch (Exception e) {
e.printStackTrace();
}
}
}