[JVM] JVM과 Class Loader

NoFlue·2023년 1월 8일
0

JVM

목록 보기
1/2
post-thumbnail

⛔️ 본 포스팅은 JVM을 공부한 내용을 바탕으로 작성한 글입니다. 틀린 내용 및 피드백이 필요한 부분을 발견하신다면 지적해주시면 감사드리겠습니다 :)

자바를 처음 배울 때, JVM 을 들어보았다. 당시엔 '자바 코드를 컴파일 해주는 가상 머신이구나' 정도로만 이해하고 넘어갔기 때문에 JVM의 역할을 대수롭지 않게 여겼다.
그리고 현재 CS 공부를 하는 지금, C언어로 작성되어 있는 자료구조 책을 통해 공부하면서 의문점이 생겼다.

C언어는 malloc, free 함수를 사용해 동적 할당을 해 메모리 관리를 할 수 있는데 자바는 어떻게 관리를 할까?

이러한 계기말고도 JVM를 이해한다면 코드를 보다 효율적으로 작성할 수 있다는 생각에 JVM과 GC의 역할, 동작 원리를 알아보게 되었다.

JVM의 탄생 배경

C/C++ 컴파일러는 컴파일 환경과 실행 환경이 다를 경우, 프로그램이 동작하지 않는 문제점이 있다. 운영체제 혹은 CPU 아키텍처에 따라 기계어를 해석하는 방식이 다르기 때문이다.
물론 다른 환경에서도 실행할 수 있는 크로스 컴파일이라는 방식을 도입해 해결할 수 있지만 다양한 디바이스가 늘어날 수록 해당 환경에 맞는 각각의 기계어로 해석해야하는 번거러움이 있다.

다양한 환경에 의존하지 않고 컴파일 및 실행을 하기 위해서 JVM 이 탄생하게 되었다.

JVM 구조

자바 소스 코드(.java)자바 컴파일러(javac.exe) 를 통해 바이트 코드(.class) 로 컴파일한다. 하지만 바이트 코드를 바로 실행한다면 OS에 맞는 기계어로 해석되지 않기 때문에 JVM을 통해 실행 환경에 맞는 기계어로 해석해 줄 수 있다.

JVM은 Class Loader Execution Engine Runtime Data Area Native Method Interface(JNI) Native Interface Library 로 구성되어 있다.

간단하게 JVM의 동작 방식을 요약하면

  1. 바이트 코드를 Class Loader를 통해 동적으로 로드한다.
  2. 로드된 바이트 코드들을 엮어서 Runtime Data Area에 배치한다.
  3. Runtime Data Area에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다.

이번 포스트에서는 Class Loader 에 대한 내용을 정리한다.

Class Loader

Class Loader는 컴파일된 클래스 파일(.class) 들을 동적으로 메모리에 로딩하는 역할을 한다. 이때 동적으로 로딩한다는 것은 컴파일 타임이 아닌 런타임 때 클래스 파일이 필요하여 실행할 경우 메모리에 올린다는 것이다.

Class Loader는 Loading Linking Initializing 단계로 나뉘어져 있다.

Loading

클래스 파일을 읽고, JVM의 메소드 영역에 클래스 정보변수, 메소드 정보 를 저장한다.

Linking

클래스 파일을 사용하기 위해 검증하는 단계다.

Verifying

읽은 클래스의 바이너리 데이터가 유효한지 검증한다. 만약 유효하지 않을 경우 VerifyError 를 던진다.
만약 믿을 만한 클래스 파일만 있을 경우 성능 향상을 위해 검증을 넘길 수 있다.

Preparing

static 변수, 메소드와 같은 클래스가 필요로 하는 메모리 공간을 할당한다.

Resolving

클래스의 상수 풀 내 심볼릭 레퍼런스를 힙 메모리에 위치한 인스턴스에 대한 레퍼런스로 변경한다.

심볼릭 레퍼런스
Primitive Type을 제외한 모든 타입을 메모리 주소 기반의 레퍼런스가 아닌 참조하는 대상의 이름만을 지칭한 것

Initializing

확보한 메모리 공간에 클래스의 static 값들을 할당한다.

Class Loader 종류

각각의 클래스 파일들이 기본으로 제공받는 클래스 파일인지 개발자가 정의한 클래스 파일인지에 따라 Class Loader의 종류가 크게 3가지로 나뉘어지며, 계층 구조로 이루어져 있다.

Bootstrap Class Loader

Bootstrap Class Loader는 Class Loader 중 최상위 클래스이며, JVM 시작 시 최초로 실행되는 Class Loader 이다. 운영체제에 맞게 실행되어야 하므로 네이티브 코드로 작성되어 있다.

  • Java 8 : jre/lib/rt.jar 의 자바 API 라이브러리를 로드한다.
  • Java 9 이후 : rt.jar 이 사라지고 /lib 내에 모듈화되었기 때문에 Class Loader 내 최상위 클래스만 로드한다.

네이티브 코드로 작성 되어있어서 String.class.getClassLoader() 를 호출하면 null 을 반환한다.

println(String::class.java.classLoader)
// null

Extension Class Loader

Bootstrap Class Loader를 다음으로 우선 순위를 가지는 Class Loader 이다.

  • Java 8 : URLClassLoader 를 상속하며, jre/lib/extjava.ext.dirs 환경 변수로 지정된 폴더 내 클래스들을 로드한다.
  • Java 9 이후 : jre/lib/extjava.ext.dirs 를 지원하지 않고, Java SE 의 모든 클래스JCP(Java Community Process)에 의해 표준화된 모듈의 클래스 를 로드한다.
    BuiltinClassLoader 를 상속하여 ClassLoader 의 내부 static 클래스로 구현되었으며, PlatformClassLoader 로 변경되었다.

Application Class Loader

-classpath 또는 -cpJAR안에 있는 Manifest 파일의 Class-Path 속성값으로 지정된 폴더 내 클래스 를 로드한다.
개발자가 직접 작성한 클래스들은 대부분 Application Class Loader에 의해 로드된다.

  • Java 8 : URLClassLoader 를 상속한다.
  • Java 9 이후 : BuiltinClassLoader 를 상속하여 ClassLoader 의 내부 static 클래스로 구현되었으며, SystemClassLoader 로 변경되었다..

개발자가 작성한 클래스의 ClassLoader를 호출하면 AppClassLoader 가 나온다.

class Test{}

println(Test::class.java.classLoader)
// jdk.internal.loader.ClassLoaders$AppClassLoader

println(Test::class.java.classLoader.parent)
// jdk.internal.loader.ClassLoaders$PlatformClassLoader
// parent는 부모가 아닌 위임에 대한 상위 클래스를 반환

Class Loader 3가지 원칙

클래스 로더는 위 사진과 같이 동작을 한다. 이렇게 동작하는 원리는 아래에서 설명하는 3가지 원칙과 관련이 있다.

Delegation Principle(위임 원칙)

클래스 로딩이 필요할 때, 클래스 로더가 상위 클래스 로더에게 로딩을 위임하는 것을 말한다.
위 코드에서 보여준 parent 가 위임을 할 상위 클래스 로더를 반환한다.

Visibility Principle(가시범위 원칙)

하위 클래스 로더는 상위 클래스 로더가 로딩한 클래스를 볼 수 있지만, 상위 클래스 로더는 하위 클래스 로더가 로딩한 클래스를 볼 수 없다는 것을 말한다.
이러한 가시범위 법칙이 없을 경우, Bootstrap ClassLoader에서 로드한 java.lang.String 클래스를 Application ClassLoader에서 사용하지 못한다. 또한 상위 클래스 로더가 하위 클래스 로더에 의해 로딩된 클래스를 볼 수 있다면 클래스 로더를 구분한 의미가 없어진다.

Uniqueness Principle(유일성 원칙)

하위 클래스 로더는 상위 클래스 로더가 로드한 클래스를 다시 로드하지 않아야 하는 것을 말한다.
유일성을 식별하는 기준은 클래스의 바이너리 이름이다.

println(String::class.java) // java.lang.String
println(ClassLoader::class.java) // java.lang.ClassLoader

Binary Name에 대한 내용은 StackOverflow 에 올라온 질문의 답변을 보면 될 것 같다.

참고문헌

[JAVA] ☕ JVM 내부 구조 & 메모리 영역 자세히 정리
[Java] JVM의 클래스 로더란?
[Java] 자바 클래스로더(Class Loader)
Oracle Chapter 5. Loading, Linking, and Initializing
우아한Tech [10분 테코톡] 🎅무민의 JVM Stack & Heap
Tecoble JVM에 관하여 - Part 2, ClassLoader
Java 클래스로더 훑어보기

profile
앱 개발에 호기심이 많은 대학생 개발자 :3

0개의 댓글