클래스로더
클래스로더는 자바 프로그램 실행 시 클래스 파일들을 로드하고 메모리에 올리는 역할을 수행하는 시스템의 일부입니다.
프로그램의 동작 및 클래스 파일들의 관리를 담당하며, 여러 개의 클래스로더가 계층적으로 구성되어 작동합니다.
로딩과정
- 로딩(Loading)
클래스로더가 클래스 파일의 바이트 코드를 읽어와 메모리로 로드합니다. 이때 로드된 클래스 파일은 각 JVM 플랫폼에 맞는 바이트코드로 변환되며, 이후 실행 가능한 형태로 변환됩니다. - 링크(Link)
클래스 파일을 사용하기 위해 검증하는 과정입니다.- 검증(Verification)
로드된 클래스 파일의 바이트 코드가 올바르게 구성되었는지 검증하는 단계 입니다. 클래스가 자바 언어 명세 및 JVM 명세에 명시된대로 구성되어 있는지 검사합니다. 검증에 실패하면 java.lang.VerifyError를 발생시킨다. - 준비(Preparation)
클래스로더가 클래스의 static 변수 및 상수를 메모리 공간에 할당하고 기본값으로 초기화됩니다. - 분석(Resolve)
클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 실제 힙 영역의 메모리 레퍼런스로 교체한다.
- 검증(Verification)
- 초기화(Initalization)
클래스의 정적 변수 및 상수를 초기화 하는 단계 입니다. static 변수들을 설정한 값으로 초기화 합니다.
클래스로더 로딩 과정
- 먼저 클래스가 로딩되었는지 확인하기 위해 클래스로더에게 하위계층에서 상위 계층으로 가며 각 클래스로더의 캐시를 확인합니다.
- 애플리케이션 클래스 로더 → 확장 클래스 로더 → 부트스트랩 클래스로더로 요청이 위임된다.
- 부트스트랩 클래스로더는 jdk/jre/lib에 해당 클래스가 있는지 확인하고, 없으면 확장 클래스로더에 위임한다.
- 확장 클래스 로더는 jdk/jre/lib/ext에 해당 클래스가 있는지 확인하고, 없으면 애플리케이션 클래스로더에 위임한다.
- 애플리케이션 클래스 로더는 환경 변수로 지정된 class path에 해당 클래스가 있는지 확인하고 존재하지 않으면 예외를 발생시킨다.
만약 중간에 클래스로더 캐시에서 로딩되었던 클래스를 찾아도 최상위 클래스로더까지 요청합니다.
이런식으로 동작하는 이유는 가시범위 원칙(Visibility Principle)과 관련이 있습니다.
가시범위 원칙은 하위 클래스 로더는 상위 클래스로더가 로딩한 클래스를 볼 수 있지만, 상위 클래스로더는 하위 클래스로더가 로딩한 클래스를 볼 수 없다는 원칙이다.
또한 유일성 원칙(Uniqueness Principle)은 하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 다시 로딩하지 않게 해서 로딩된 클래스의 유일성을 보장하는 것입니다.
각 클래스로더의 역할
부트스트랩 클래스로더
자바에서 기본적으로 제공하는 API 등과 같은 표준 JDK 클래스들을 로드합니다.
jre/lib 에 있는 핵심 라이브러리와 java.lang.Object, java.lang.ClassLoader와 같은 최소한의 자바 클래스만을 로드합니다.
가장 상위 클래스 로더이므로, 운영체제에 맞게 네이티브 코드로 쓰여있습니다.
확장 클래스 로더
jre/lib/ext나 환경변수 java.ext.dirs에 지정된 경로(확장 디렉토리)에서 클래스를 로드합니다.
자바 9 이후부터 확장 메커니즘이 제거되어 클래스 이름이 PlatformClassLoader로 변경되었습니다.
애플리케이션 클래스로더
클래스 패스로 지정한 경로에서 클래스를 로드합니다.
즉, 개발자가 직접 작성한 .class 파일을 로드합니다.
클래스 로더의 특징
- 가시적인 규약
- 상위 클래스로더가 찾지 못한 클래스를 하위 클래스로더가 찾는 경우가 존재하게되므로, 상위 클래스로더는 하위 클래스로더가 로드한 클래스를 볼 수 없습니다. 이를 가시적인 규약이라고 합니다.
- 위임형 로드 요청상위 클래스 로더를 하나씩 거슬러 올라가며 확인하게 되는데, 올라가는 도중 클래스를 발견해도 끝까지 올라가 확인을 하고, 제일 상위 클래스로더에 있는 클래스를 로더합니다.
- 클래스 로더 캐시 확인
- 상위 클래스 로더
- 자기 자신
- 위임형 로드 모델을 통해 클래스 중복 로딩을 방지하여 클래스의 유일성을 보장합니다.
- 클래스로더는 로드 요청시 먼저 상위 클래스로더에게 로드를 위임한 후, 상위 클래스로더가 로드할 수 없는 경우, 자신이 클래스를 로드하게 됩니다.
- 클래스 언로드 불가
- Java에서는 클래스 언로드를 지원하지 않습니다. 즉, 한번 로드된 클래스는 메모리에서 제거가 되지 않습니다.
왜 클래스 로더를 계층적으로 사용하는가?
- 모듈화가 가능하다.
- 클래스의 충돌을 피할 수 있다.
- 효율적으로 사용할 수 있다.(사용자 정의 클래스 로더 사용시)
- 동적으로 클래스나 리소스를 추가할 수 있다.
- 운영중에 수정된 클래스를 동적으로 리로딩하기 용이하다.
로딩 방식
로딩 방식
두 로딩의 차이점은 클래스나 리소스가 어떤 시점에 로딩되는지에 대한 차이입니다.
로드타임 동적 로딩(Load-Time Dynamic Loading)
명시적 로딩은 코드 상에서 클래스나 리소스를 필요한 시점에 직접 로딩하는 방식입니다.
- loadClass()
- Class.forName()
- getResource()
위 메서드를 사용하여 클래스나 리소스를 로드할 때 발생합니다.
즉, 코드의 특정 위치에서 로딩이 필요한 경우 사용됩니다.
런타임 동적 로딩(Run-Time Dynamic Loading)
함축적 로딩은 클래스나 리소스가 필요한 시점에 자동으로 로딩되는 방식입니다.
자바에서 클래스나 리소스는 해당 내용이 처음으로 참조되거나 사용되는 시점에 로딩됩니다.
즉, 이 방식은 자원의 사용 시점까지 불필요한 자원 로딩을 피해 효율적 입니다.(ex : 정적 메서드)
'Back-end' 카테고리의 다른 글
static lazy 로딩 (0) | 2023.08.19 |
---|---|
정적 vs 동적 in Java (0) | 2023.08.18 |
static (0) | 2023.08.16 |
Hash, HashTable, HashMap, CuncurrentHashMap (0) | 2023.08.16 |
ArrayList vs LinkedList vs Array (0) | 2023.08.16 |