이전에 다뤘던 JVM에 이어서 클래스 로더를 좀 더 깊이있게 다뤄보고자 하는 마음으로 포스팅해본다.
자바 애플리케이션이 실행될 때 JVM은 필요할 때마다 클래스를 메모리에 로드하고 이를 활용한다. 이 런타임에 필요한 클래스를 로드하고 연결하는 과정에서, 클래스 로더는 해당 클래스가 어디에서 왔는지를 식별하고 메모리의 특정 위치에 올린다. 자바는 클래스가 처음 사용될 때 클래스 로딩이 이루어지므로, 자바의 클래스 로더는 동적 클래스 로더라고도 불린다. 이 특성 덕분에 자바는 메모리를 효율적으로 사용할 수 있다.
클래스 로더는 단순히 클래스를 로드하는 것을 넘어, 애플리케이션에서 플러그인이나 모듈 기반 아키텍처를 구현할 때 중요한 역할을 한다. 예를 들어, 특정 기능을 플러그인 형태로 분리하여 동적으로 로드하고 싶을 때, 클래스 로더를 사용하면 프로그램의 실행 중에 별도의 클래스를 불러와 애플리케이션을 확장할 수 있다.
또한, JVM에서는 커스텀 클래스 로더를 직접 구현할 수도 있어, 보안을 강화하거나 메모리 로딩을 최적화하는 다양한 기법을 적용할 수 있다. 예를 들어, 특정 경로의 클래스만 로드하거나 네트워크나 파일 시스템의 특정 리소스에서만 클래스를 로드하도록 제한할 수 있다.
즉, 클래스 로더를 통해 자바 애플리케이션은 필요할 때만 필요한 클래스를 불러와 모듈화를 통한 유연성을 갖출 수 있다. 객체지향 프로그래밍에서 지향하는 모듈화와 캡슐화를 JVM 차원에서 지원하는 역할을 클래스 로더가 수행하는 셈이다.
자바는 런타임에 클래스 로딩과 링크하는 과정을 거치며, 이 과정을 통해 동적으로 클래스를 로드하는 기능을 제공한다. 이 기능을 담당하는 것이 바로 클래스 로더다.
클래스 로더는 3가지의 기본 클래스로더가 존재하고 이를 동작에 대한 원칙으로 구분한다. 지금부터 클래스로더의 종류와 원칙에 대해 알아보자 !
클래스 로더는 JVM이 자바 클래스를 어떻게 메모리에 로드할지를 결정하는 역할을 담당한다. 이 각각의 클래스 로더는 자바 런타임의 특정 부분에 있는 클래스를 로드하도록 설계되어 있다.
부트스트랩 클래스 로더는 최상위 클래스 로더로, JVM이 시작될 때 가장 먼저 실행된다. 이 로더는 java.lang
, java.util
등의 기본적인 자바 표준 라이브러리를 로드하며, JVM 내부에 내장된 네이티브 코드로 구현되어 있다. 부트스트랩 클래스 로더는 최상위 레벨의 클래스 로더로서, 자바 애플리케이션이 로드되는 과정에서 최우선 순위를 가진다.
확장 클래스 로더는 부트스트랩 클래스 로더의 다음 계층에 위치하며, java.ext.dirs
디렉토리에 있는 클래스들을 로드한다. 자바 확장 라이브러리를 로드하는 역할을 담당하며, 자바 애플리케이션에서 추가적인 기능이나 확장 모듈을 로드할 때 이 확장 클래스 로더가 사용된다. 이 클래스 로더를 통해 시스템에서 필요한 추가 라이브러리를 JVM에 추가할 수 있다.
시스템 클래스 로더는 애플리케이션 클래스 로더라고도 불리며, 자바 애플리케이션이 실행될 때 클래스 경로에 있는 클래스들을 로드한다. 이 로더는 일반적으로 애플리케이션 코드나 개발자가 지정한 클래스들을 로드하는 역할을 담당하며, classpath
에 포함된 모든 파일을 검색하여 필요한 클래스를 로드하게 된다.
로드: 클래스 파일이 필요한 경우, JVM은 클래스 로더를 통해 해당 클래스 파일을 로드한다. 이때 파일의 경로나 네트워크 위치를 탐색하여 클래스를 메모리에 올리는 작업을 수행한다.
링크: 클래스 로딩이 완료되면, 그 클래스가 참조하는 다른 클래스들과의 관계를 설정하는 "링크" 과정을 거친다. 링크는 다시 검증(Verification), 준비(Preparation), 해결(Resolution) 세 단계로 이루어진다.
초기화: 링크가 완료되면, 클래스의 정적 변수와 정적 블록이 실행되며 초기화가 이루어진다. 이때 클래스가 처음으로 메모리에 올라가며, 이후 해당 클래스를 사용할 준비가 된다.
클래스 로더는 일반적으로 부모-자식 관계로 구성되며, 자식 클래스 로더는 부모 클래스 로더에 클래스를 먼저 위임한 후 찾지 못한 경우에만 자신이 클래스를 로드한다.
클래스 로더가 클래스를 로드할 때 가장 상위 클래스 로더부터 하위로 내려가며 로딩을 시도한다는 원칙이다. 만약 상위 클래스 로더가 해당 클래스를 찾지 못하면, 하위 클래스 로더가 직접 클래스를 로드하게 된다. 이 원칙으로 JVM은 중복 로딩을 방지하고 메모리를 절약할 수 있다.
상위 클래스 로더에서 로드한 클래스는 하위 클래스 로더에서 볼 수 있지만, 하위 클래스 로더에서 로드한 클래스는 상위 클래스 로더에서 볼 수 없다는 원칙이다. 즉, 클래스 로더는 각 로더의 클래스 영역을 구분하고 보호할 수 있다.
클래스가 JVM 내부에서 유일하게 로드된다는 것을 보장해주는 원칙이다. 동일한 클래스를 여러 번 로드하면 메모리 낭비는 물론이고 알지못하는 버그를 유발할 수 있다. 이를 방지하기 위해, 클래스 로더는 이미 로드된 클래스를 재사용하여 유일성을 보장한다.
Java 9부터는 모듈이 추가되었다. 기존의 classpath 외에 module path가 추가되어서 클래스 로더의 기존 구조에 모듈 개념을 도입하여, 애플리케이션의 보안성과 모듈화 기능을 더 강화했다.
그 외 클래스 로더의 구조의 변경점이 있지만 너무 길어지므로.. 생략