[Java] 클래스 로더(Java Classloader)

bien·2025년 1월 13일
0

Java_Spring_Backend

목록 보기
2/10

클래스 로더(Classloader)

  • 이름을 알고 있는 특정 클래스에 대한 정의(Bytestream)를 가져오는 역할을 수행
  • 부트스트랩 클래스 로더
    • JVM에서 라이브러리로 취급(rt.jar, tools.jar)되는 것들을 로드 (핫스팟에서는 C++로 구현)
  • 플랫폼 클래스 로더 (기존 확장 클래스 로더)
    • 클래스 라이브러리 로드
  • 애플리케이션 클래스 로더
    • sun.misc.Launcher$AppClassLoader를 의미

Java 클래스 로딩

클래스 파일 형식

  • Java 소스(.java)는 컴파일되어 바이트 스트림을 포함한 .class파일이 됨
  • .class 파일은 클래스의 형식과 버전 정보를 포함

오류 유형

  • 컴파일 타임 오류: 문법적 오류
  • 런타임 오류: 프로그램 실행 중 발생하는 오류 (Linking 과정 포함)

C++과의 차이점

  • Java는 생성자만 존재하고 소멸자 개념이 없음
  • 객체 소멸은 GC가 자동으로 관리

Linking 과정

Initialization 시점에 도달하고 나서야 생성자 호출
Linking과정이 지나야 생성자가 호출된다.

  1. Verification 검증
  2. Preparatino 준비
  3. Resolution 해석

  • 클래스 로딩 및 링킹 과정이 모두 런타임에 이뤄짐
  • 실행 성능이 일부 저하될 수 있으나 높은 확장성과 유연성을 제공하는 공간
    • 인터페이스만 맞으면 Runtime에 구현 클래스를 결정하지 않을 수 있음
    • 클래스 로더는 실행할 프로그램 코드를 네트워크로 수신하는 것도 가능
  • 해석(Resolution) 단계는 동적 바인딩(혹은 늦은 바인딩)을 지원할 목적으로 초기화 후로 지연될 수 있음

검증 (Verification)

심벌 참조 검증

  • 상속 관계와 의존성을 확인하는 심벌 참조는 다음과 같이 동작한다:
    • 자식 클래스가 부모 클래스에 대해 존립 수준의 의존성을 가질 때, 부모 클래스가 먼저 로딩되어야 한다
    • 예시로 MyTestEx클래스는 MyTest 클래스에 의존적이므로 MyTest가 먼저 로딩되어야 한다.
    • 메서드 호출, 상속 관계, 클래스 로딩 순서등의 정보를 포함한다.

바이트코드 실행과 메모리

  • 바이트 코드 실행 시:
    • 실행 코드는 메모리의 특정 위치에 저장
    • 실제 메모리 위치 정보를 찾아 바인딩
    • 이를 통해 메서드 호출과 연산이 가능해진다.
      • 실행 시 필요한 클래스, 메서드, 필드 등의 모든 논리적 참조 정보를 하이레벨 언어 수준에서 심볼로 표현한 것이 심볼 참조다.

보안 검증

  • JVM은 보안을 위해 다음을 수행한다
    • 바이트코드 레벨에서 보안 위협 검사
    • OS에 영향을 미칠 수 있는 코드 검증
      • 이 과정은 시간이 많이 소요되는 심층적인 검증 과정

jvm이 한정하는 영역을 못벗어나도록 애플리케이션을 제한한다.
이런 요소때문에 보안과 관련해 C나 C++ 보다 훨씬 안정적이다

준비(Preparation) 및 해석(Resolution)

  • 객체 인스턴스가 저장될 메모리 공간을 확보하고 0으로 초기화
  • 생성자 호출 전 상태 (필드 초깃값은 생성자 호출 시 변경)
    • 단 심볼릭 상수 필드는 값을 할당
  • 해석은 상수 풀의 심벌 참조를 직접 참조로 대체하는 과정

메모리 구조

  • 참조 변수 t는 스택 영역에 저장
  • 실제 객체 인스턴스는 힙 영역에 저장
  • 예시: MyTest t = new MyTest
    • t는 Stack에 위치한 참조 변수
    • 실제 객체는 Heap 영역에 위치
    • 참조 변수는 힙의 객체 주소를 가리킴

초기화와 생성자

jvm은 인스턴스가 저장될 공간을 몽땅 확보하고 0 초기화 한다.
Field에 0을 초기화(Field = 0;)하지 않아도 기본적으로 0 초기화를 시행한다.
메모리가 준비되면, 이는 아직 생성자가 호출되기 전이다.
따라서 필드 초깃값은 생성자에서 바꾸면 그게 우선한다.

메모리 준비가 끝나고 초기화 되면서 생성자가 호출될 때, 메모리의 값을 가서 조작한다.

해석(Resolution) 과정

  • 심볼릭 참조를 실제 메모리 참조(직접 참조)로 변환하는 과정
    • (참조) 이 과정을 특이하게 해석이라고 부른다.
  • 메서드나 필드 호출 시 실제 메모리 위치를 찾아 바인딩
  • 모든 참조가 실제 메모리 위치와 연결되는 과정 수행

해석 단계에서 의존관계에 있는 다른 클래스 로딩 여부를 결정하는데, 이 때 실패하면 의존성 있는 클래스를 못가져와서 로딩 실패가 발생한다.
Preparation은 메모리 확보 및 메타데이터 집어넣는 작업을 수행하는데, 이 내부에서 어떤 내용들이 이뤄지는지만 알고, GC가 어떻게 활용하는지만 알면 될 것 같다.
Initialization(사용 직전 단계)에서 생성자 호출하고, 사용단계로 넘어간다. 클래스가 Unloading되는 시점은 가비지 컬렉터가 결정할 일이기 때문에 자바에서는 이 부분에 개입하지 않는 것이 잘하는 것이다.

Heap 영역에 객체 생성

  • JVM은 객체 저장을 위한 메모리 공간을 확보 후 0으로 초기화 (단, 객체 헤더 제외)
  • 객체 초기화를 위한 구성설정 실시
    • 클래스 이름 및 메타 정보 확인 방법
    • 객체에 대한 해시코드
    • GC 세대 나이
  • 생성자 호출

객체 구조

  • 인스턴스의 두 주요 영역
    • 실제 데이터 영역: 인스턴스 필드 정보 저장
    • 메타 데이터 영역: 객체 관리 정보, GarbageCollector, 동시성 이슈 lock 관련 정보까지도 저장

메타 데이터 구성 요소

  • 클래스 이름 및 메타 정보
  • 해시코드 (인스턴스 식별용 고유값)
  • 인스턴스의 나이 (GC 관련)
  • Garbage Copllection 관련 정보
    • GC가 인스턴스의 메모리 위치를 옮길 때 나이를 기반으로 collecting 가능성을 고려하며 옮긴다.
  • 동시성 제어를 위한 lock 정보

초기화 프로세스

  1. 메모리 확보 및 0 초기화
  2. 메타 데이터 값 넣어주어 설정
  3. 클래스 준비 완료
  4. <init> 메서드를 통해 생성자 호출
  5. 필드 초기화

이런 Java 객체 레이아웃, 구조를 Java Object Layout이라고 부른다.

profile
Good Luck!

0개의 댓글