[JAVA] JVM - Class Loader

impala·2022년 12월 27일
0

JAVA

목록 보기
3/6
post-thumbnail

Class Loader

JVM의 Class Loader는 자바 컴파일러에 의해 컴파일된 파일(.class)을 JVM으로 로드하여 런타임 메모리영역에 올리는 역할을 한다.


Class Loader 작동 과정

JVM의 Class Loader는 로딩 -> 링크 -> 초기화 순으로 진행된다.
각 단계에서 하는 일은 다음과 같다.

  • 로딩 : 클래스를 읽어오는 과정
  • 링크 : 레퍼런스를 연결하는 과정
  • 초기화 : static값을 초기화하고 변수를 할당하는 과정

Loading

Loading은 Class Loader가 .class파일을 읽고 그 내용에 따라 적절한 Binary Data를 만든 뒤 Runtime Data Area의 Method Area에 저장하는 작업이다.

  • Method Area에 저장되는 데이터
    - 클래스의 Type정보(클래스, 인터페이스, Enum등)
    - 클래스의 메소드, 변수
    - FQCN(Fully Qualified Class Name) : 클래스가 속한 패키지명을 모두 포함한 이름

Linking

Class Loader의 두번째 작업인 Linking은 세 단계로 이루어진다.

  1. Verify : .class형식 파일이 유효한지 확인. Byte Code가 조작될 경우 JVM에러를 발생시킨다
  2. Prepare : 클래스의 static변수, 기본값에 필요한 메모리를 준비하는 과정
  3. Resolve : Symbolic Reference를 실제 Reference로 교체하는 과정(Optional)
    • Symbolic Reference : 객체를 실제 메모리 주소가 아닌 객체의 이름으로 참조하는 것

아래 코드에서 foo라는 참조변수가 Heap에 저장된 실제 Foo 인스턴스를 가리킬 수 있도록 연결하는 작업이 Resolve 단계에서 일어난다.

Foo foo = new Foo();

Initialization

Linking의 Prepare단계에서 확보한 메모리 영역에 클래스에서 static으로 선언된 변수와 메소드의 값들을 할당하고 초기값을 채운다.

static final String bar = "bar";

예를 들어 위의 코드를 보면 "bar"라는 문자열을 Prepare단계에서 준비한 메모리영역에 할당하고, 메모리의 레퍼런스를 변수 bar 에 연결하는 일련의 과정이 Initialization단계에서 일어난다.


ClassLoader의 종류

Class Loader는 기본적으로 제공되는 클래스인지 사용자가 정의한 클래스파일인지에 따라 세 가지 수준으로 나뉜다.

  1. Bootstrap ClassLoader

    • 최상위 ClassLoader로써 다른 모든 ClassLoader의 부모이다.
    • JVM을 구동시키기 위한 가장 필수적인 라이브러리와 클래스들(java.lang.Object, Class, ClassLoader)을 JVM에 로드
    • jre/lib/rt.jar에 있는 클래스들을 로드
    • Native Code로 작성됨
  2. Extention ClassLoader

    • BootStrap ClassLoader다음으로 우선순위를 가지는 ClassLoader
    • 확장 자바 클래스들을 로드한다.
    • (Java8) URLClassLoader를 상속하며, jre/lib/ext에 있는 모든 클래스를 로드
    • (Java9 이후) Platform Loader로 변경되었으며, URLClassLoader가 아닌 BuiltinClassLoader를 상속한다. Inner Static 클래스로 구현됨
  3. Application ClassLoader (System ClassLoader)

    • 사용자 정의 클래스를 로드
    • CLASSPATH에 있는 클래스들을 로드
    • 사용자가 ClassLoader를 구현하여 사용하는 경우 Application ClassLoader를 상속받아 구현

클래스 로딩 과정

  1. JVM Method Area에 클래스가 로드되어 있는지 확인한다. 만약 로드되어 있는 경우 해당 클래스를 사용한다.
  2. JVM Method Area에 클래스가 로드되어있지 않는 경우, Application ClassLoader에 클래스 로드를 요청한다.
  3. Application ClassLoader는 Extention ClassLoader에 요청을 위임하고, Extention ClassLoader는 Bootstrap ClassLoader에 요청을 위임한다.
  4. Bootstrap ClassLoader는 Bootstrap CLASSPATH(jdk/jre/lib)에 해당 클래스가 있는지 확인하고, 클래스가 없을 경우 Extention ClassLoader에게 요청을 넘긴다.
  5. Extention ClassLoader는 Extention CLASSPATH(jdk/jre/lib/ext)에 해당 클래스가 있는지 확인하고, 클래스가 없을 경우 Application ClassLoader에게 요청을 넘긴다.
  6. Application ClassLoader는 Application CLASSPATH에 해당 클래스가 있는지 확인하고, 클래스가 존재하지 않는 경우 ClassNotFoundException 을 발생시킨다.

정리하자면 JVM의 Method Area에 클래스가 없는 경우 ClassLoader로 요청을 보내고 최상위 ClassLoader까지 요청을 위임한 뒤 최상위 ClassLoader부터 필요한 클래스를 찾아 내려오고, Application ClassLoader에서도 클래스를 찾지 못하는 경우 예외를 던진다.


제약조건

  1. Delegation Model(위임 모델)
    • ClassLoader는 클래스 또는 리소스를 찾기 위해 요청을 받았을 때, 상위 ClassLoader에게 책임을 위임하는 Delegation Model을 따른다.
  1. Visibility(가시성 제한)
    • 하위 ClassLoader는 상위 ClassLoader가 로드한 클래스를 볼 수 있지만, 반대로 상위 ClassLoader는 하위 ClassLoader가 로드한 클래스를 알 수 없다
  1. Unique Classes

    • 하위 ClassLoader는 상위 ClassLoader에서 로드한 클래스를 다시 로드하지 않는다
  2. Hierarchy(계층 구조)

    • ClassLoader는 부모-자식 관계를 이뤄 계층구조로 생성된다.
    • 최상위 ClassLoader는 Bootstrap ClassLoader이다
  3. Can not Unload Classes(클래스 언로드 불가)

    • ClassLoader는 클래스를 로드할 수는 있지만 언로드할 수는 없다.
    • 대신, 현재 Classloader를 삭제하고 새로운 Classloader를 생성하는 방법을 사용할 수 있다.

Dynamic Class Loading

자바의 클래스 로딩은 클래스가 참조되는 시점에 JVM에 코드가 링크되고, 실제 런타임시점에 로딩되는 동적 로딩을 거친다. 즉, JVM은 미리 모든 클래스에 대한 정보를 Method Area에 로딩하지 않고 필요할 때 클래스로더에게 클래스로딩을 요청하여 Method Area에 올림으로써 효율적으로 메모리를 관리한다.


Load-time Dynamic Loading

하나의 클래스를 로딩하는 과정에서 동적으로 다른 클래스를 로딩하는 것

Example Code

public class HelloWorld { 
        public static void main(String[] args) { 
                System.out.println("안녕하세요!"); 
        } 
}
  1. JVM이 시작되고 Bootstrap ClassLoader에서 Object클래스를 로드한다
  2. ClassLoader는 HelloWorld클래스를 로딩하기 위해 HelloWorld.class파일을 읽는다
  3. HelloWorld클래스를 로딩하는 과정에서 필요한 클래스인 java.lang.String과 java.lang.System을 로드한다

Run-time Dynamic Loading

클래스를 로딩할 때가 아닌, 코드를 실행하는 순간에 클래스를 로딩하는 것

Example Code

public class RuntimeLoading { 
        public static void main(String[] args) { 
                try { 
                        Class cls = Class.forName(args[0]); 
                        Object obj = cls.newInstance(); 
                        Runnable r = (Runnable) obj; 
                        r.run(); 
                } catch (Exception e) {
                        e.printStackTrace();
                }
        }
}
  1. Class.forName()메소드가 실행되기 전까지 RuntimeLoading클래스에서 어떤 클래스를 참조하는지 알 수 없다.
  2. 따라서 RuntimeLoading 클래스를 로딩할 때에는 어떤 클래스도 읽어오지 않고, Class.forName(args[0])이 호출되는 순간에 args[0]에 해당하는 클래스를 로딩한다.

참고자료

0개의 댓글