JVM의 구조
JVM은 Java Virtual Machine 의 약자로, 자바로 작성한 코드를 실행하는 가상머신이다. 현재는 많이 흐려졌지만, Java가 WORA(Write Once Run Anywhere) 를 구현하기 위해 물리적인 머신이 아닌 가상머신에서 동작하도록 구현되었다.
Java로 작성한 코드는 전체적으로 아래 그림과 같은 과정을 통해 실행된다.
자바는 정적 로딩이 아니라 동적로딩을 한다. 즉, 컴파일타임이 아니라 실행타임에 클래스를 디스크에서 읽어와 메모리에 로드한다. 이런 로딩 작업을 하는 JVM의 구성요소를 클래스 로더라고 부른다. 클래스 로더는 3가지 원칙을 가지고있다.
클래스로더의 3원칙
1. 계층구조와 위임.
자바의 클래스 로더들은 서로 부모 - 자식관계를 이루어 계층을 이룬다. 또한, 클래스 로드가 필요할 때, 하위 클래스 로더로 처음 요청이 들어오는데, 하위 클래스 로더는 이를 부모로 넘기고, 최상위인 부트스트랩 클래스 로더에서부터 다시 아래로 내려오며 클래스를 로드한다.
2 가시성 제한.
하위 클래스 로더는 상위 클래스 로더가 로드한 클래스를 볼 수 있지만, 상위 클래스로더에서 하위 클래스 로더가 로드한 클래스를 볼 수 없다.
3. 유일성 원칙.
같은 클래스를 여러번 로드하면 안된다. 즉, 하위 클래스 로더는 상위 클래스로드가 로드한 클래스를 다시 로드하면 안된다.
이런 원칙은 java.lang.ClassLoader 클래스의 loadClass 메서드에 포함되어있다.
클래스 로더의 계층구조
위에서 말한 클래스 로더의 계층구조에 대해 좀 더 자세히 보면 아래 그림과 같다.
최상위 클래스 로더인 부트스트랩 클래스 로더는 JVM 실행시 최초로 실행되는 클래스 로더로 Object 클래스를 비롯한 자바 API 클래스들을 로드하는 클래스 로더이다. 구체적으로 {$JAVA_HOME}/jre/lib 에 위치한 클래스들을 로드한다. 이 부트스트랩 클래스 로더는 자바코드가 아니라 네이티브 코드로 구현 되어있다.
그 아래에 확장 클래스 로더가 있다. 이 클래스 로더는 자바의 다양한 보안 확장기능들을 로드한다. 구체적으로 {$JAVA_HOME}/jre/lib/ext 에 위치한 클래스를 로드한다.
그 아래에는 시스템 클래스 로더가 있다. 애플리케이션 클래스 로더라고도 불린다. 이 클래스 로더는 사용자가 코드로 작성한 클래스들을 로드한다. 구체적으로 $CLASSPATH 의 클래스들을 로드한다.
사용자 정의 클래스 로더는 사용자가 직접 코드로 작성한 클래스 로더로, 주로 Tomcat 같은 WAS나 Spring같은 프레임워크에서 자신들의 클래스를 로드하기 위해 사용한다.
위의 각 클래스 로더에 대한 설명은 자바 8까지의 설명이다. 자바 9부터 모듈이 도입되면서 각 클래스 로더의 명칭과 클래스 로더가 로드하는 클래스, 자바코드 상에서의 상세 구현방식의 변경이 있었다.
클래스 로더의 위임방법
클래스 로더가 클래스를 로드할 때 어떤 식으로 위임하는지 자세히 보면 다음과같이 정리할 수 있다.
- 클래스가 로드 되어있는지 확인한다. 없으면 애플리케이션 클래스 로더에 로드를 요청한다.
- 애플리케이션 클래스 로더는 요청을 확장 클래스 로더에게 위임하고, 확장 클래스 로더는 이를 다시 부트스트랩 클래스 로더로 넘긴다.
- 부트스트랩 클래스 로더는 요청된 클래스가 부트스트랩 클래스패스({$JAVA_HOME}/jre/lib)에 위치하는지 확인하고 위치한다면 로드하고 없으면 확장 클래스 로더가 요청을 처리하도록 한다.
- 확장 클래스 로더도 마찬가지로 요청된 클래스가 확장 클래스패스에 위치하는지 확인하고 위치한다면 로드하고 없으면 애플리케이션 클래스 로더가 요청을 처리하도록 한다.
- 애플리케이션 클래스 로더는 클래스패스에 클래스가 있는지 확인하고, 있다면 로드하고 없으면 ClassNotFoundException을 발생시킨다.
클래스 로더의 클래스 로딩 과정
클래스 로더가 어떤 클래스 로더에서 어떤 클래스를 로드 할지 결정된 이후 클래스 로더에서 클래스를 로드 하는 과정은 크게 Loading - Linking - Initializing 의 3단계로 구성된다.
Loading
.class 파일을 읽어서 JVM의 메모리(메서드 영역)에 로드한다. 이 시점에서 class 파일이 JVM 스펙에 맞는지 확인하고, 자바 버전을 체크한다.
Linking
Linking은 다시 3단계로 나뉘어진다.
Verifying(검증)
앞에서 읽어 들인 class 파일이 자바 언어 명세와 JVM 명세를 제대로 따르는 지 검증하는 절차이다. 로드작업 전체에서 가장 복잡하고 오래 걸리는 작업이다.
Preparing(준비)
클래스가 필요로 하는 메모리를 할당하고, 클래스에서 정의된 필드, 메서드, 인터페이스들을 나타내는 데이터를 준비한다.
Resolving(분석)
클래스의 상수 풀 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경한다.
Initializing
위에서 할당한 메모리에, 클래스의 static 필드, 메서드를 할당한다.
'Java > JVM' 카테고리의 다른 글
[JVM] JVM의 구조 - 3. 힙 영역과 GC (0) | 2021.11.12 |
---|---|
[JVM] JVM의 구조 - 2. 런타임 데이터 영역(RDA) (0) | 2021.11.11 |