최근 APM(Application Performance Monitoring) 시스템을 담당하게 되면서, 기존 애플리케이션을 분석하는 과정에 있는데, 그동안 몰랐던 다양한 개념들에 대해 많이 알아가고 있는 중이다.
그리고 그 중에 JVM의 한 영역이 ClassLoader에 대해 간단한 역할 정도만 알고 있었는데, 조금 더 깊게 알아볼 기회가 생겼고, 그 부분에 대해 공부한 점을 정리하고자 한다. 이전에는 클래스로더를 단순히 ".class 파일을 읽어 바이너리 코드로 변환한다" 정도로만 알고 있었다.
클래스로더는 기본적으로 3가지로 구분된다(물론 Java 버전에 따라 조금씩 차이가 있다)
Java 8을 기준으로 보면..
- BootStrap ClassLoader
- Extension ClassLoader
- Application ClassLoader
로 구분할 수 있다. 각 클래스 로더를 살펴보자.
Bootstrap ClassLoader
부트스트랩 클래스로더는 3가지의 기본 클래스로더 중 최상위의 클래스로더 이다. Java 8 기준으로는 jre/lib/rt.jar 에 있는 JDK 클래스 파일을 로딩한다.
다만 부트스트랩 클래스로더는 Java 코드가 아니라 Native C로 구현되어 있다.
Extension ClassLoader
익스텐션 클래스로더는 jre/lib/ext 디렉토리나 java.ext.dirs 환경 변수로 지정된 디렉토리 내의 클래스 파일을 로딩한다.
자바 코드로 구현되어 있으며 sun.misc.Luancher 클래스 내의 static 클래스로 구현되어 있고, URLClassLoader를 상속하고 있다.
Application ClassLoader
애플리케이션 클래스로더는 classpath 또는 jar 파일 안에 있는 Manifest 파일의 Class-Path 속성값으로 지정된 디렉토리에 있는 클래스를 로딩한다.
마찬가지로 sun.misc.Luancher 클래스 내의 static 클래스로 구현되어 있고, URLClassLoader를 상속하고 있다.
자바 코드로 구현되어 있으며, 개발자가 작성하는 대부분의 클래스는 애플리케이션 클래스로더에 의해 로딩된다.
클래스 로더의 3가지 원칙
1) Delegation Principal - 클래스 로딩 작업을 상위 클래스 로더에 위임
- 위임 원칙은 클래스 로딩이 필요할때 3개의 기본 클래스로더 상위로 클래스 로딩을 위임하는 것을 말한다.
- 새로운 클래스를 로딩할때 아래와 같은 방식으로 클래스 로딩을 수행한다.
- VM의 Method Area에 클래스가 로드되어 있는지 확인한다. 만일 로드되어 있는 경우 해당 클래스를 사용한다.
- Method Area에 클래스가 로드되어 있지 않을 경우, 애플리케이션 클래스로더에 클래스 로드를 요청한다.
- 애플리케이션 클래스로더는 익스텐션(확장) 클래스로더에 클래스 로드를 요청한다.
- 익스텐션 클래스로더는 부트스트랩 클래스로더에 클래스 로드를 요청한다.
- 부트스트랩 클래스로더는 부트스트랩 Classpath(JDK/JRE/LIB)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 확장 클래스로더가 요청을 수행하도록 한다.
- 익스텐션 클래스로더는 확장 Classpath(JDK/JRE/LIB/EXT)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 애플리케이션 클래스로더가 요청을 수행하도록 한다.
- 애플리케이션 클래스로더는 애플리케이션 Classpath에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 ClassNotFoundException을 발생시킨다.
2) Visibility Principal - 하위 클래스로더는 상위를 볼 수 있지만, 상위 클래스로더는 하위를 볼 수 없다.
- 예를들어 java.lang.Object 처럼 상위 클래스로더에서 로딩한 클래스는 하위 클래스로더가 볼 수 있어야 사용할 수 있을 것이다.
- 상위 클래스로더도 하위 클래스로더가 로딩한 클래스를 볼 수 있게 되면 이러한 구분의 개념이 희미해지기 때문에 반대의 경우는 불가능하다.
3) Uniqueness Principal - 유일성 원칙
- 유일성 원칙은 상위 클래스로더가 로드한 클래스를 하위 클래스로더에서 로드하지 않아야 한다는 원칙
- 이 원칙이 지켜지지 않으면 JVM에 동일한 클래스가 여러개 로드되는 상황에 처할 수 있다.
그렇다면 한가지 의문이 생긴다.. 왜 굳이 번거롭게 클래스로더를 나누어 두었을까?
클래스 로더를 구분하여 사용하는 이유
- 모듈화가 가능하다.
- 클래스의 충돌을 피할 수 있다.
- 효율적인 사용 - 사용하지 않는 클래스를 언로드하여 메모리 사용량을 줄일 수 있다.
- 동적으로 클래스나 리소스를 추가할 수 있다.
각 클래스로더가 담당하는 패키지 내에 어떠한 클래스들이 존재하는지, Java 9 이후로는 어떠한 점이 변경되었는지 추가할 필요가 있다.
* 출처
https://leeyh0216.github.io/posts/java_class_loader/
'개발 > Java' 카테고리의 다른 글
[Java] 예외의 종류(Checked, UnChecked, Error) (0) | 2023.07.30 |
---|---|
[Java] Enum 에 대해 (0) | 2023.07.09 |
[Java]Try-with-resource (0) | 2022.08.16 |
[Java] 자바의 메모리 영역(2) (0) | 2022.07.03 |
[Java]Serialization(직렬화) (0) | 2022.05.25 |