NDM

[Java] 자바 동작 원리와 JVM 1편 : Class Loader 본문

Java

[Java] 자바 동작 원리와 JVM 1편 : Class Loader

ndm.jr 2022. 4. 28. 11:33

목차

  • Java는 어떻게 동작하는가?
  • JVM구조
    • ClassLoader 동작원리

 


Java는 어떻게 동작하는가?

Java 동작 과정

 

동작 순서

  1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다.
  2. 자바 파일(.java)이 자바 컴파일러에 의해 자바 바이트 코드(.class)로 변환된다.
  3. 클래스 로더를 통해 자바 바이트 코드를 JVM으로 필요한 시점에 로딩한다.
  4. 해석된 바이트 코드는 런타임 데이터 영역에 배치되어 실질적인 수행이 이루어지게 된다.
  5. 실행 과정 속에서 JVM은 필요에 따라 GC와 같은 관리 작업을 수행한다

 

주의 깊게 봐야 할 것

  • Java는 바이트코드라는 중간언어로 바뀌고, JVM은 그 바이트코드를 실행하며 프로그램이 실행된다
  • OS에서 메모리를 할당받아 JVM에서 실행되므로, 운영체제에 독립적이다
  • 컴파일러와 인터프리터
  컴파일러 인터프리터
빌드 타임 모든 소스코드에 대한 기계어 생성 아무것도 안함
런타임 빌드타임에 생성한 기계어를 기계로 보냄 코드를 한줄씩 읽어 기계어로 변환, 기계로 보냄
더보기

과거의 Java는 인터프리터만을 사용했고, 매우 느렸다는 비판이 있었다.
이유는 한줄 씩 읽어 실행했고, 중복된 코드 또한 다시 인터프리팅 하는 과정을 겪어야 했기 때문!

때문에 이러한 속도를 개선하고자 JIT Compiler가 등장하게 된다.

  컴파일러 인터프리터 JIT Compiler
빌드 타임 모든 소스코드에 대한 기계어 생성 아무것도 안함 .java 파일을 중간언어인 바이트코드로 변환
런타임 빌드타임에 생성한 기계어를 기계로 보냄 코드를 한줄씩 읽어 기계어로 변환, 기계로 보냄 바이트코드를 기계어로 변환
캐싱을 통해 같은 코드가 여러번 호출 될 경우 기존의 코드 사용
더보기

이러한 JIT Compiler의 등장으로, 인터프리터의 속도에 대한 문제를 어느정도 개선할 수 있었다.
하지만 중간언어가 등장했기 때문에, 런타임에 느리다는 비판을 피할수 없었다.

 


JVM


클래스로더

  • 자바의 클래스들은 시작 시 로드되는 것이 아니라, 어플리케이션에 의해 필요할 때 로드된다. 
    클래스로더는 런타임에 클래스를 동적으로 로드해 주는 모듈이다

 

클래스로더 종류

 

  1. BootStrap Class Loader
    • JAVA_HOME\lib에 있는 코어 자바 API를 제공한다. 최상위 우선순위를 가진 클래스 로더
      자바 클래스를 로드할 수 있는 자바 자체의 클래스 로더와 최소한의 자바 클래스(java.lang.Object, Class, ClassLoader)만을 로드한다.
  2. Extension Class Loader(Platform Class Loader)
    • java.ext.dirs 환경 변수에 설정된 디렉토리의 클래스 파일을 로드하고, 이 값이 설정되어 있지 않은 경우 ${JAVA_HOME}/jre/lib/ext 에 있는 클래스 파일을 로드
  3. System Class Loader
    • 자바 프로그램 실행 시 지정한 Classpath에 있는 클래스 파일 혹은 jar에 속한 클래스들을 로드한다. 쉽게 말하자면, 우리가 만든 .class 확장자 파일을 로드한다.
    • 애플리케이션 클래스패스(애플리케이션 실행할 때 주는 -classpath 옵션 또는 java.class.path 환경 변수의 값에 해당하는 위치)에서 클래스를 읽는다

동작 방식

  1. JVM의 메소드 영역에 클래스가 로드되어 있는지 확인한다. 만일 로드되어 있는 경우 해당 클래스를 사용한다.
  2. 메소드 영역에 클래스가 로드되어 있지 않을 경우, 시스템 클래스 로더에 클래스 로드를 요청한다.
  3. 시스템 클래스 로더는 확장 클래스 로더에 요청을 위임한다.(↑)
  4. 확장 클래스 로더는 부트스트랩 클래스 로더에 요청을 위임한다.(↑)
  5. 부트스트랩 클래스 로더는 부트스트랩 Classpath(JDK/JRE/LIB)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 확장 클래스 로더에게 요청을 넘긴다.(↓)
  6. 확장 클래스 로더는 확장 Classpath(JDK/JRE/LIB/EXT)에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않을 경우 시스템 클래스 로더에게 요청을 넘긴다.(↓)
  7. 시스템 클래스 로더는 시스템 Classpath에 해당 클래스가 있는지 확인한다. 클래스가 존재하지 않는 경우 ClassNotFoundException을 발생시킨다.

 

단계 별 하는 일

  1. 로딩(Loading)
    • 클래스 로더가 .class 파일을 읽고 그 내용에 따라 적절한 바이너리 데이터를 만들고 “메소드” 영역에 저장.
    • 이 때, 메소드 영역에 저장되는 데이터
      • FQCN : 패키지 명과 경로가 모두 합해진 클래스 정보
      • Class / Interface / Enum 정보
      • Method / 변수 정보
  2. 링크(Linking)
    • verify : .class파일의 유효성 체크. Symbolic Refernce를 가진다
    • prepare : static변수와 기본값에 필요한 메모리가 세팅되며, 클래스의 메소드, 변수, 인터페이스 등에 필요한
      데이터 구조를 준비한다.
    • Resolve : Symbolic Reference를 Method Area의 타입으로 직접 참조하기 시작한다
      더보기
      Symbolic Reference :
      • 참고하는 클래스의 특정 메모리 주소를 참조 관계로 구성한 것이 아니라, 참조하는 대상의 이름만을 지칭한 것이다. 자바 바이트 코드(.class)가 JVM에 올라가게 되면 심볼릭 레퍼런스는 이름에 맞는 객체의 물리적인 주소를 찾아서 연결하는 작업을 수행한다.
      • 기본 자료형을 제외한 모든 타입을 명시적인 메모리 주소 기반의 레퍼런스가 아니라 심볼릭 레퍼런스를 통해 참조한다.
  3. 초기화(Resolve)
    • Static 변수 초기화 ( Static 블록이 있다면 실행 )