[JAVA] 클래스 로더

D A S H B O A R D
D E V E L O P
S E C U R I T Y
주요내용
Reference

 클래스 로더(class loader)

자바는 동적으로 클래스를 읽어오기 때문에 프로그램이 실행중인 런타임에서 JVM과 연결된다.
한 번에 메모리에 모든 클래스를 로드하는 것이 아닌, 필요한 순간에 해당 클래스(.class) 파일을 찾아 메모리에 로딩해주는 역할
JVM의 실행 엔진이 사용할 수 있도록 Runtime Data Area의 메소드 영역에 적재
로딩, 링크, 초기화 단계 처리
로딩
자바 바이트 코드(.class)를 읽어 적절한 바이너리 데이터를 만들고 메모리의 메소드 영역에 저장
이 과정에서 JVM 스펙이 맞는지 확인 & Java Version 확인
저장 데이터
Fully-Qualified Class Name (클래스 로더, 클래스 패키지 정보, 패키지 이름, 클래스 이름을 모두 포함한 값)
Class, Interface, Enum을 구분하여 저장
메소드의 변수
링크
검증 : 읽은 클래스의 바이너리 데이터가 유효한 것인지 확인 → 이 과정에서 오버헤드가 발생할 가능성이 있어, -Xverify:none 을 통해 검증을 진행하지 않을 수 있다.
준비 : 클래스의 static 변수와 기본 값에 필요한 메모리 공간을 준비
분석 : 사용하는 환경에 따라 동작 유무가 정해짐 → 이 과정에서 심볼릭 메모리 레퍼런스를 메서드 영역에 있는 실제 힙 메모리 영역에 있는 인스턴스에 대한 래퍼런스로 교체
심볼릭 메모리 레퍼런스란?
참고하는 클래스의 메모리 주소를 참조하는 것이 아니라, 참조 대상의 이름을 지칭하는 것
해당 링크 → 분석 과정에서 심볼릭 메모리 레퍼런스에 있는 참조 대상의 이름을 보고 주소를 연결한다.
초기화
링크 단계의 준비에서 준비한 메모리 공간(힙)에 static 값들을 초기화 및 SuperClass 초기화와 해당 클래스 초기화 진행
실제 위 3단계를 실행하며 위임 원칙을 만족시키는 API
loadClass() : 지정된 이름을 가지는 클래스를 로드
해당 메서드 내부에서 findLoadedClass() 호출 - 이미 로드된 내역이 있는지 확인
findClass() : loadClass시 load 된 class가 없을 시, load 하고자 하는 class의 이름으로 클래스 파일 탐색
defineClass() : 위의 findClass메서드에서 원하는 class파일을 찾은 경우 .class 파일로부터 바이트 배열을 class객체로 변환

 클래스 로더의 구조

JAVA 8

1.
Bootstrap Class Loader (Primordial Class Loader)
자바의 기본 클래스로더 중 최상위 클래스로더로서 parent ClassLoader가 존재하지 않음
${JAVA_HOME}/jre/lib/rt.jar에 담긴 JDK 클래스 파일을 로딩(다만, 옵션 -Xbootclasspath 옵션으로 path 수정 가능)
Native C로 구현돼 있어, String.class.getClassLoader()는 그냥 null을 반환 ( 자바 코드에 의해서 instance화 불가)
2.
Extension Class Loader
BootstrapClassLoader를 parent로 가지고 있음
${JAVA_HOME}/jre/lib/ext 폴더나 java.ext.dirs 환경 변수로 지정된 폴더에 있는 클래스 파일을 로딩
자바로 구현되어 있으며, sun.misc.Launcher$ExtClassLoader로 구현되어있고, URLClassLoader를 상속
사용자의 classpath를 수정하지 않고 확장으로 쉽게 갈 수 있는 기능을 제공
3.
Application Class Loader
자바의 -classpath(또는 -cp) 옵션이나, jar 파일 안에 있는 Manifest 파일의 Class-Path 속성 값으로 지정된 폴더에 있는 클래스 로딩
개발자가 애플리케이션 구동을 위해 직접 작성한 대부분의 클래스는 여기서 로딩됨
ClassLoader.getSystemClassLoader()를 통해서 얻을 수 있음

JAVA 9+

1.
Bootstrap Class Loader
모듈화 시스템 도입으로 ${JAVA_HOME}/jre/lib/rt.jar가 없어짐에 따라 로딩하는 클래스의 범위가 전반적으로 축소
경로가 ${JAVA_HOME}/lib/module 로 변경
기존에 parent를 BootstrapClassLoader로 가지고 있던 ClassLoader의 경우 parent에 대한 경로 수정이 필요
2.
Platform Class Loader
${JAVA_HOME}/jre/lib/ext 폴더나 java.ext.dirs 환경 변수를 지원하지 않음
Java SE의 모든 클래스와 JDK-specific run-time 클래스들을 여기서 로딩
URLClassLoader를 상속받지 않은 ClassLoaders 클래스의 내부 static 클래스로 구현
3.
System Class Loader
classpath, modulepath에 있는 클래스 로딩
Runtime 클래스는 프로그램과 운영체제간의 상호 작용을 위한 메서드들이 정의

 클래스 로더의 원칙 및 특징

3가지 원칙

설명은 JAVA 8 기준으로! → JAVA 9+도 같은 원칙을 기반으로 동작
1.
Delegation : 위임
어떠한 클래스 파일을 로딩할 때, 해당 로딩 요청이 부모 클래스 로더들로 거슬러 올라가 BootstrapClassLoader(최상위 ClassLoader)에 다다른 후 그 밑으로 로딩 요청을 수행
a.
ClassLoaderRunner는 자기 자신을 로딩한 애플리케이션 클래스로더에게 Internal 클래스 로딩을 요청한다.
b.
클래스 로딩 요청을 받은 애플리케이션 클래스로더는 Internal을 스스로 직접 로딩하지 않고 상위 클래스로더인 익스텐션 클래스로더에게 위임한다.
c.
클래스 로딩 요청을 받은 익스텐션 클래스로더도 Internal을 스스로 직접 로딩하지 않고 상위 클래스로더인 부트스트랩 클래스로더에게 위임한다.
d.
부트스트랩 클래스로더는 rt.jar에서 Internal을 찾아서
d-1. 있으면 로딩 후 반환하고
e.
없으면 익스텐션 클래스로더가 jre/lib/ext 폴더나 java.ext.dirs 환경 변수로 지정된 폴더에서 Internal을 찾아서
e-1. 있으면 로딩 후 반환하고
f.
없으면 애플리케이션 클래스로더가 클래스패스에서 Internal을 찾아서
f-1. 있으면 로딩 후 반환하고
g.
없으면 ClassNotFoundException이 발생한다.
2.
Visibility : 가시범위
하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 볼 수 있지만, 상위 클래스로더는 하위 클래스로더가 로딩한 클래스를 볼 수 없다
3.
Uniqueness : 유일성
하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 다시 로딩하지 않게 해서 로딩된 클래스의 유일성을 보장
유일성을 식별하는 기준은 클래스의 binary name

2가지 특징

Unload Impossibility
클래스 로더에 의해 로딩된 클래스들은 JVM 상에서 삭제할 수 없다
Reflection
Unloading 기능을 우회적으로 구현하는 방법은 Class를 로드한 Class Loader 자체를 삭제하고, 새로운 Class Loader를 만들어서 다시 Class를 로드하면, reload 되는 것처럼 작동하는 것을 Reflection이라 한다.
Hierarchical
계층적 구조를 가지도록 생성(부모-자식의 관계) 부모 클래스 로더에서 자식 클래스 로더를 가지는 형태