Java/개념

JVM 동적 클래스 로딩

TheWing 2021. 2. 24. 22:43

JVM 동적 클래스 로딩

클래스 로더란 '.class' 바이트 코드를 읽어 들여 class 객체를 생성하는 역할을 담당한다. 즉, 클래스 로더는 클래스가 요청될 때 파일로부터 읽어 메모리로 로딩하는 역할을 하며 자바 가상 머신의 중요한 요소 중 하나다.

※ 클래스 로더가 classpath라는 환경 변수에 등록된 디렉토리에 있는 모든 클래스들을 먼저 JVM에 로딩한다. JVM에 로딩된 클래스만이 JVM에서 객체로 사용할 수 있다. 클래스 로딩은 클래스를 로딩하는 시점 또는 실행 중간에도 할 수 있다.

자바의 클래스 로딩은 세부적으로 로딩, 링크, 초기화라는 세 단계 과정을 거친다.

  • 로딩 : 클래스 파일을 바이트 코드로 읽어 메모리로 가져오는 과정
  • 링크 : 가장 복잡한 과정으로, 읽어본 바이트 코드가 자바 규칙을 따르는지 검증하고, 클래스에 정의된 필드, 메소드, 인터페이스들을 나타내는 데이터 구조를 준비하며, 그 클래스가 참조하는 다른 클래스를 로딩한다.
  • 초기화 : 슈퍼 클래스 및 정적 필드를 초기화한다.

동적 Java 클래스 로딩은 주로 Java Reflection. Java Reflection JVM에서 실행되는 애플리케이션의 런타임 동작을 검사하거나 수정할 수 있는 기능을 제공합니다. 또한 런타임에 특정 클래스에서 사용될 메서드와 속성을 결정하는 데 사용됩니다.

따라서 프로그램을 변경할 필요없이 프로그램에 추가 기능을 추가할 수 있는 프로그래머와 사용자 모두에게 유연성을 제공하는 플러그인 아키텍처를 대상으로 하는 경우. Java 동적 Java 클래스 로딩 Java Reflection 은이 접근 방식을 달성하기 위한 메커니즘입니다.

 

로드타임 동적 로딩(load-time dynamic loading)과 런타임 동적 로딩(run-time dynamic loading)

로드타임 동적 로딩(load-time dynamic loading)

public class HelloWorld {
     public static void main(String[] args) {
        System.out.println("안녕하세요!");
     }
  }

HelloWorld 클래스를 실행하였다고 가정

부트스트랩 클래스로더가 생성된 후에, 모든 클래스가 상속받고 있는 Object 클래스를 읽어온다. 그 이후에, 클래스로더는 명령행에서 지정한 HelloWorld 클래스를 로딩하기 위해, HelloWorld.class 파일을 읽는다. HelloWorld 클래스를 로딩하는 과정에서 필요한 클래스가 존재한다. 바로 java.lang.String과 java.lang.System이다. 이 두 클래스는 HelloWorld 클래스를 읽어오는 과정에서, 즉 로드타임에 로딩된다. 이 처럼, 하나의 클래스를 로딩하는 과정에서 동적으로 클래스를 로딩하는 것을 로드타임 동적 로딩이라고 한다.

Object 클래스를 읽어온다 → HelloWorld클래스를 로딩하기 위해 HelloWorld.class 파일을 읽는다 → 로딩과정에서 java.lang.String, System이 필요하다 → 클래스를 읽어오는 과정에서 로드타임에 로딩

런타임 동적 로딩(run-time dynamic loading)

public class HelloWorld1 implements Runnable {
   public void run() {
      System.out.println("안녕하세요, 1");
   }
}
public class HelloWorld2 implements Runnable {
   public void run() {
      System.out.println("안녕하세요, 2");
   }
}
public class RuntimeLoading {
     public static void main(String[] args) {
        try {
           if (args.length < 1) {
              System.out.println("사용법: java RuntimeLoading [클래스 이름]");
              System.exit(1);
           }
           Class klass = Class.forName(args[0]);
           Object obj = klass.newInstance();
           Runnable r = (Runnable) obj;
           r.run();
        } catch(Exception ex) {
           ex.printStackTrace();
        }
     }
  }

위 코드에서, Class.forName(className)은 파리미터로 받은 className에 해당하는 클래스를 로딩한 후에, 그 클래스에 해당하는 Class 인스턴스(로딩한 클래스의 인스턴스가 아니다!)를 리턴한다. Class 클래스의 newInstance() 메소드는 Class가 나타내는 클래스의 인스턴스를 생성한다. 예를 들어, 다음과 같이 한다면 java.lang.String 클래스의 객체가 생성된다.

Class klass = Class.forName("java.lang.String");
Object obj = klass.newInstance();

따라서, Class.forName() 메소드가 실행되기 전까지는 RuntimeLoading 클래스에서 어떤 클래스를 참조하는 지 알수 없다. 다시 말해서, RuntimeLoading 클래스를 로딩할 때는 어떤 클래스도 읽어오지 않고, RuntimeLoading 클래스의 main() 메소드가 실행되고 Class.forName(args[0])를 호출하는 순간에 비로서 args[0]에 해당하는 클래스를 읽어온다. 이처럼 클래스를 로딩할 때가 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것을 런타임 동적 로딩이라고 한다.

.java 파일로 작성되었던 소스코드가 어떻게 JVM위로 로딩되는지 과정

.java 파일 → bytecode 변환후 로딩 → 메모리에 저장 → 로딩 → 링크 → 초기화

결론

로드타임 동적 로딩은(load-time dynamic loading)의 약자이고

public class HelloWorld {
        public static void main(String[] args) {
                System.out.println("Hello World!!!");
        }
}

라는 HelloWorld 클래스를 실행하였다고 가정하고 말해보겠습니다.
부트스트랩 클래스로더가 생성된 후에 모든 클래스가 상속 받고 있는 Object클래스를 읽어오고 그 후에 클래스로더는 명령행에서 지정한 HelloWorld 클래스를 로딩하기 위해서, 컴파일된 HelloWorld.class 파일을 읽습니다. HelloWorld 클래스를 로딩하는 과정에서 필요한 클래스가 존재하는데 현재 예시에서는 java.lang.Stringjava.lang.System 클래스입니다. 이 두 클래스는 HelloWorld 클래스를 읽어오는 과정에서 로드타임에 로딩이 됩니다.
이렇게 하나의 클래스를 로딩하는 과정에서 동적으로 클래스를 로딩하는 것을 로드타임 동적로딩이라고합니다.
간략하게 순서를 나열해보면 Object Class를 읽는다 ->HelloWorld 클래스를 Loading 하기 위해서 HelloWorld.class 파일을 읽는다 -> 로딩 과정에서 java.lang.String, System 클래스를 읽는다 -> 클래스를 읽어오는 과정에서 로드타임에 로딩한다

런타임 동적 로딩은(Run-time dynamic loading)의 약자입니다.

public class HelloWorld {
        public static void main(String[] args) {
                Class c = Class.forName(args[0]);
        }
}

라는 HelloWorld 클래스를 실행하였다고 가정하고 말해보겠습니다.
객체를 참조하는 순간에 동적으로 Loading 하는 방식입니다. 위 코드에서, Class.forName(args[0])은 파리미터로 받은 (args[0])에 해당하는 클래스를 로딩한 후에, 그 클래스에 해당하는 Class 인스턴스를 리턴하게 됩니다. Class.forName() 메소드가 실행되기 전까지는 HelloWorld 클래스에서 어떤 클래스를 참조하는지는 알수 없고 이것을 알려면 인자로 넘어오는 args[0]가 인수로 넘어온 후에나 알 수 있습니다. 이처럼 클래스를 로딩할 떄가 아닌 코드를 실행하는 순간에 클래스를 로딩하는 것을 런타임 동적 로딩이라고 합니다.

Reference

로드타임 동적로딩 런타임 동적로딩

클래스로더

로드타임 동적로딩 런타임 동적로딩

동적 클래스 로딩 예

정적 클래스 로딩과 동적 클래스로딩

java 클래스 변수가 어떻게 메모리에 올라가는지?

java 컴파일에서 실행까지