오늘 회의 때 나온 Class.forName 과 ClassLoader.loadClass의 중요한 동작 차이.

Class.forName(String clazzName, boolean init, ClassLoader loader) 은 지정한 ClassLoader를 통해 해당 ClassLoader가 define하지 않은 Class라 할지라도 JVM에서 해당 ClassLoader에 캐시하게 되어 있고..
ClassLoader.loadClass(String clazzName) 은 무조건 defineClass를 실행한 ClassLoader에만 해당 Class를 캐시.

아래 블로그 참고.

Class.forName caches defined class in the initiating class loader

결과적으로 Class.forName을 사용하면 경우에 따라 효과적인 클래스  캐시를 구현할 수도 있다는 것. (불필요한 user classloader cache 없이..)

참고로 ClassLoader.loadClass(String clazzName, boolean resolve)에서 두번째 인자인 resolve는 원래 의도하기에는 클래스 로딩 시에 참조하는 클래스들에 대한 linking을 실행하기 위한 것이나 (eager linking) 한번도 JVM에서 구현된 적이 없으므로 무시한다. Java에서는 아직까지는 항상 lazy linking만 지원하는 셈.

P. S 1) resolveClass 구현 즉, eager linking 구현 코드

ClassLoader에서 resolveClass를 실행해도 아무 일도 일어나지 않길래 왜 그러나 봤더니..
(resolveClass는 지정한 Class의 바이트코드에 선언된 link해야 할 Class들을 모두 link해주는 역할을 해야 함)
Hotspot JVM에서 구현을 하지 않았을 뿐임 ㅠ_ㅠ;
즉, Hotspot JVM에서는 link가 해당 클래스를 항상 처음 사용할 때(즉, 메소드 호출을 하는 등)에만 일어남...

java/lang/ClassLoader.java

protected final void resolveClass(Class c) {
resolveClass0(c);
}

private native void resolveClass0(Class c);

jdk/src/share/native/java/lang/ClassLoader.c

JNIEXPORT void JNICALL
Java_java_lang_ClassLoader_resolveClass0(JNIEnv *env, jobject this,
jclass cls)
{
if (cls == NULL) {
JNU_ThrowNullPointerException(env, 0);
return;
}

JVM_ResolveClass(env, cls);
}

실제 jvm 구현체를 보면

hotspot/src/share/vm/prims/jvm.cpp

JVM_ENTRY(void, JVM_ResolveClass(JNIEnv* env, jclass cls))
JVMWrapper("JVM_ResolveClass");
if (PrintJVMWarnings) warning("JVM_ResolveClass not implemented");
JVM_END

즉, resolveClass를 호출해도 아무 일도 하지 않네요.

P.S 2) 실제 발생하는 lazy resolving (즉, class linking).

JVM에서 class linking (resolving)의 구현 방식. CONSTANT_Class_info 에 대한 설명 부분.

아래 글 참고

The Linking Model

자바 class는 loaded, verified, prepared 상태를 거쳐 defineClass가 완료된 후 resolve phase로 들어갈 수 있다.(ClassLoader.loadClass에서 두번째 인자를 true로 준 경우)
보통은 resolve를 이 시점에서 하지 않는다. resolve를 하거나 혹은 하지 않거나 완료되면 initialize를 할 수 있다.(Class.forName에서 두번째 인자를 true로 준 경우)

resolve는 CONSTANT_Class_info 를 채워 실제 linking을 일으키는 과정이다. link 즉, resolve 시점에서는 initialize되지도 않으며 처음 사용(호출)될 때 initialize가 일어난다. 물론 link를 찾을 수 없다면 NoClassDefFoundError가 그때 (처음 사용될 때) 던져지게 된다.

댓글

이 블로그의 인기 게시물

Java G1 GC의 특성에 따른 Full GC 회피 튜닝 방법

Heap Dump 분석을 통한 Perm Area Memory Leak 원인 진단

맥북프로 13인치 2010년 버전의 하드웨어 업그레이드 산전수전 경험기