Java는 동적으로 클래스를 읽어오므로, 프로그램이 실행중인 런타임에서야 모든 코드가 JVM과 연결됩니다. 이 동적 로드를 담당하는 부분이 JVM 클래스 로더입니다. 즉, 런타임중에 JVM의 메소드 영역에 동적으로 .class를 로드하는 역할을 합니다.
1. 로딩 (Loading)
Java에서의 로딩 및 링킹 과정은 전통적인 컴파일, 실행 환경과는 다르게 보안, 플랫폼 독립성, 동적 실행환경의 장점을 제공합니다. 여기서 동적 실행 환경이란 프로그램이 실행되는 중에 코드나 리소스를 로드 할 수 있게 됩니다.
- classpath 환경변수에 지정된 디렉토리나 jar파일, 네트워크 리소스가 포함된 미리 정의된 여러 위치를 검색합니다.
- 여러 종류의 클래스 로더를 사용하여 클래스들을 로드합니다.
bootstrap class loader - JVM 자체에 포함된 핵심 Java API 클래스 (기본 자료구조, 입출력 함수 등)을 JRE의 lib 디렉토리에 로드합니다.
extension class loader - 확장 라이브러리에 클래스를 로드합니다. lib/ext 또는 java.ext.dirs 시스템 속성에 지정된 경로에서 클래스를 로드합니다.
application class loader - 사용자가 정의한 클래스와 classpath에 지정된 라이브러리의 클래스를 로드합니다.
위의 세 클래스 로더가 순서대로 진행되며 사용자는 java.lang.ClassLoader 클래스를 확장하여 사용자 정의 클래스 로더를 구현할수도 있습니다. - 바이트 코드 로드 - 로더가 클래스의 위치를 확인하면 그 위치에서 바이트 코드를 읽어 JVM의 메서드 영역에 저장합니다. 메타데이터와 함께 바이트 코드도 저장됩니다.
2. 연결 (Linking)
컴파일러 혹은 인터프리터가 생성한 여러 모듈이나 객체 파일들을 하나의 실행 파일로 결합하는 과정
1. 검증 (Verification) - 로드된 클래스의 바이트코드가 올바른지 확인합니다.
2. 준비 (Preparation) - 클래스나 인터페이스의 정적 변수들을 기본 값으로 초기화하며 필요한 메모리를 할당합니다.
3. 해석 (Resolution) - JVM이 클래스, 메소드, 필드에 대한 심볼릭 참조를 직접적인 참조로 변환합니다.
3. 초기화 (Initialization)
클래스 파일의 코드를 읽으며 class와 interface의 값들을 지정한 값들로 초기화합니다. 이때 JVM은 멀티 쓰레딩으로 작동하는데 이 때문에 동시성을 고려해주어야합니다.
Q. 동시성 문제란?
자바 프로그램에서 여러 스레드가 동시에 작업을 수행할 때 발생하는 문제들을 의미합니다
클래스 로드 시점, 클래스 초기화 시점, 초기화 순서 등은 코드를 보면서 이해하는것이 좋은것같아 아주 잘 써진 글 링크를 남깁니다.
☕ 클래스는 언제 메모리에 로딩 & 초기화 되는가 ❓
JVM의 클래스 로더 (Class Loader) 자바의 클래스들이 언제 어디서 메모리에 올라가고 클래스 멤버들이 초기화되는지, 원리를 알기위해선 우선 JVM(자바 가상 머신)의 클래스 로더(Class Loader)의 진행
inpa.tistory.com
# 로드타임 동적로딩
프로그램 시작 시 필요한 클래스만 로드하므로 초기 시작 시간과 메모리 사용량을 최적화할 수 있습니다.
1. JVM이 시작되고 부트스트랩 클래스 로더가 생성된 후에 모든 클래스가 상속받고 있는 Object 클래스를 읽어옵니다.
2. 클래스 로더는 명령행에서 지정한 클래스를 로딩하기 위해 .class파일을 읽습니다.
3. 클래스 로딩중에 필요한 java.lang.String 등을 로딩합니다.
# 런타임 동적로딩
Class.forName(className)은 파라미터로 받은 className에 해당하는 클래스를 로딩한 후에 객체를 반환합니다. Class.forName() 메소드가 실행되기 전까지는 메소드를 포함한 클래스는 어떤 클래스를 참조하는지 알 수 없습니다. 따라서 메소드를 포함한 클래스를 로딩할때는 어떤 클래스도 읽어오지 않고, Class.forName(className)를 호출하는 순간에 비로소 className에 해당하는 클래스를 로딩합니다.
이러면 실행 시점에서 동적으로 로드할 클래스나 모듈을 결정할 수 있어, 높은 유연성을 제공합니다.
# 클래스 로더의 3가지 원칙
1. 위임 원칙 (Delegation Principle)
클래스 로더는 클래스를 찾기 위해 요청을 받았을때 상위 클래스 로더에게 책임을 위임하는 모델을 따릅니다.
- JVM의 Method Area에 클래스가 로드되어 있는지 확인한다. 만일 로드되어 있는 경우 해당 클래스를 사용
- Method Area에 클래스가 로드되어 있지 않을 경우, 애플리케이션 클래스로더에 클래스 로드를 요청
- 애플리케이션 클래스로더는 확장 클래스로더에 클래스 로드를 요청
- 확장 클래스로더는 부트스트랩 클래스로더에 클래스 로드를 요청
- 부트스트랩 클래스로더는 부트스트랩 Classpath(JDK/JRE/LIB)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 확장 클래스로더가 요청을 수행하도록 합니다.
- 확장 클래스로더는 확장 Classpath(JDK/JRE/LIB/EXT)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 애플리케이션 클래스로더가 요청을 수행하도록 합니다.
- 애플리케이션 클래스로더는 애플리케이션 Classpath에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 ClassNotFoundException을 발생
2. 가시범위 원칙 (Visibility Principle)
하위 클래스로더는 상위 클래스로더가 로딩한 클래스를 볼 수 있지만 상위는 하위가 로딩한 클래스를 볼 수 없습니다. java.lang.Object를 상위에서 로드하면 하위에서도 사용 가능 합니다.
3. 유일성 원칙 (Uniqueness Principle)
하위는 상위에서 로드한 클래스를 다시 로드하지 않아야합니다.
# References
https://tecoble.techcourse.co.kr/post/2021-08-09-jvm-memory/
https://velog.io/@jifrozen/JVM-%EA%B5%AC%EC%84%B1%EC%9A%94%EC%86%8C-1-%ED%81%B4%EB%9E%98%EC%8A%A4-%EB%A1%9C%EB%8D%94
https://velog.io/@skyepodium/%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A1%9C%EB%94%A9%EB%90%98%EA%B3%A0-%EC%B4%88%EA%B8%B0%ED%99%94%EB%90%98%EB%8A%94%EA%B0%80
https://leeyh0216.github.io/posts/java_class_loader/
https://kkang-joo.tistory.com/10
https://inpa.tistory.com/entry/JAVA-%E2%98%95-%ED%81%B4%EB%9E%98%EC%8A%A4%EB%8A%94-%EC%96%B8%EC%A0%9C-%EB%A9%94%EB%AA%A8%EB%A6%AC%EC%97%90-%EB%A1%9C%EB%94%A9-%EC%B4%88%EA%B8%B0%ED%99%94-%EB%90%98%EB%8A%94%EA%B0%80-%E2%9D%93
chatgpt
'Back-end' 카테고리의 다른 글
[JVM 동작원리] 3. Execution engine (0) | 2023.10.16 |
---|---|
[JVM 동작원리] 2. Runtime Data Area (0) | 2023.10.12 |
Java의 compile 과정 (0) | 2023.10.09 |
agile 방법론, microservice, dev-ops, cloud (0) | 2023.07.15 |
Web server 와 Web application server (0) | 2023.03.23 |