본문 바로가기
끄적끄적

JVM 구성요소 - 클래스로더

by 승승구리 2025. 6. 1.
# JVM 구성요소 - 클래스로더

 

클래스로더란?

JVM의 구성요소 중 하나로 클래스 파일을 로딩하여 메모리에 올리는 역할을 한다. 

 

클래스로더의 종류

부트스트랩 클래스로더, 플랫폼 클래스로더, 어플리케이션 클래스로더 총 3가지로 구성되어 있다.

( * 추가적인 커스텀 클래스로더도 구성이 가능하다. )

 

클래스로더의 동작방식

클래스로더는 아래와 같은 순서로 클래스파일을 메모리에 올리는 과정을 거친다.

로딩 -> 검증 -> 준비 -> 해석 -> 초기화 -> 사용 -> 언로딩

이 중에 (검증 -> 준비 -> 해석) 단계를 "링킹"이라고도 부른다.

로딩 -> 링킹 -> 초기화 -> 사용 -> 언로딩


이제 각각의 동작들이 어떠한 작업을 하는지 알아보자.

 

1. 로딩

-> 클래스 파일을 바이너리 바이트 스트림으로 읽어온다, 바이트 스트림으로 표현된 정적인 구조를 메서드 영역에서 사용하는 런타임 데이터 구조로 변환한다.

 

2. 검증

-> 클래스 파일의 바이트 스트림에 담긴 정보가 JVM 명세 조건을 만족하는지 확인한다.

-> 보안을 위협하는 코드가 없는지 확인한다.

-> 클래스 파일을 검증하는 과정은 Hotspot JVM의 클래로더 파싱 소스코드 내용을 확인하면 좋다.

-> 검증 단계를 마치면 바이트 스트림이 JVM의 메서드 영역에 저장된다.

 

3. 준비

-> 클래스변수를 메모리에 할당하고 초기값을 할당하는 단계다.

인스턴스 변수가 아닌 클래스 변수만 할당된다.

준비 단계에서 클래스 변수에 할당하는 초기값은 해당 데이터 타입의 제로값이다.

public static int value = 0;

final 키워드가 붙은 변수는 의도한 값을 할당한다.

public static final int value = 123;

 

4. 해석

JVM이 상수 풀의 심벌 참조를 직접 참조로 대체하는 과정이다.

더보기
더보기

심벌 참조란?

심벌 참조는 JVM이 구현한 메모리 레이아웃과는 아무런 관련이 없다. 참조 대상이 반드시 JVM의 메모리에 로드되어 있을 필요도 없다. 메모리 레이아웃은 JVM의 구현에 따라 달라질 수 있지만 심벌 참조는 달라지지 않는다. 왜냐하면 심벌 참조에 쓰일 수 있는 리터럴 형태는 JVM 명세의 클래스 파일 구조에 명확하게 정의되어 있기 때문이다.

더보기
더보기

직접 참조란?

포인터, 상대적 위치(오프셋) 또는 대상의 위치를 간접적으로 가리키는 핸들이다. 직접 참조는 가상 머신에 구현된 메모리 레이아웃과 밀접하게 관련된다. 따라서 똑같은 심벌 참조로부터 변환했더라도 직접 참조는 JVM에 따라 달라지는게 보통이다. 직접 참조는 참조 대상이 JVM의 메모리에 이미 존재해야 한다.

말이 어렵지만 클래스 파일을 실행하면 실제 메모리주소를 매핑시켜준다고 생각하면 된다.

C 컴파일러의 경우 링킹 과정을 통해 실행할 수 있는 exe파일을 만들어낸다. 해당 exe파일을 열어보면 어셈블리어로 메모리 주소가 연결되어 있는 것을 알 수 있는데, 실제로 프로그램을 실행하면 프로세스가 실행되고 메모리에 올라가게 되고, 어셈블리로 확인한 메모리 주소를 가리키게 되는 것이다.

다만 Java의 경우 동적 로딩 방식이기 때문에 클래스 파일을 로딩할때 메모리 주소가 할당된다. 그 작업이 "해석" 단계에서 하는 것이다.

 

5. 초기화

초기화 단계에 들어서면 JVM이 드디어 사용자 클래스에 작성된 코드를 실행하기 시작한다. 준비 단계에서 클래스 변수의 초기값을 해당 데이터 타입의 제로값으로 할당했는데, 초기화 단계에서 개발자가 기술한 초기값으로 할당한다.