티스토리 뷰

Java

JVM 구조

J-Mandu 2022. 3. 28. 09:00

출처 :https://www.inflearn.com/course/the-java-code-manipulation

위 사진은 JVM의 전체적인 구조입니다.


클래스 로더(Class Loader)

자바 바이트 코드를 읽어서 JVM의 실행 엔진이 사용할 수 있도록

메모리의 메소드 영역에 적재하는 역할을 합니다.

출처 :https://www.inflearn.com/course/the-java-code-manipulation

로딩 -> 링크 -> 초기화 순으로 진행됩니다.

 

1. 로딩

클래스 로더가 .class 파일을 읽고 그 내용에 따라 적절한 바이너리 데이터를 만들고, 메소드 영역에 저장됩니다.

이때 메소드 영역에 저장하는 데이터는 다음과 같습니다.

  • FQCN(Fully-Quailified Class Name) : 클래스 로더, 클래스 패키지 경로, 패키지 이름, 클래스 이름을 모두 포함한 값
  • Class, Interface, Enum
  • 메소드와 변수

로딩이 끝나면 해당 클래스 타입의 Class 객체를 생성하여 힙 영역에 저장하게 됩니다.

출처 :https://beststar-1.tistory.com/13?category=975450

위 사진은 Internal.class가 로딩하는 과정의 예시입니다.

Application -> Extension -> Bootstrap 클래스 로더의 순서대로 로딩 요청을 위임합니다.

이후 기본 라이브러리인 rt.jar -> 외부 라이브러리인 ext -> JVM이 프로그램을 실행할 때 클래스를 찾기 위한 기준이 되는 경로인 classpath 순으로 클래스 로딩을 시도하고, 없다면 ClassNotFoundException이 발생하게 됩니다.

 

2. 링크

Verify, Prepare, Reolve(optional) 세 단계로 나눠져 있습니다.

  • 검증(Verify) : .class 파일 형식이 유효한지 체크합니다.
  • 준비(Prepare) : 클래스 변수(static 변수)와 메서드, 기본값에 필요한 메모리를 준비합니다.
  • 분석(Resolve) : 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체합니다. 
    이 과정이 Optional인 이유는 이때 교체될 수도 있고, 나중에 실제 해당 레퍼런스를 사용할 때, 교체될 수도 있습니다.

3. 초기화

Static 변수를 초기화하고 값을 할당하는 과정입니다.
(static 블록이 있다면 이때 실행하게 됩니다.)

 

클래스 로더는 계층 구조로 이루어져 있으며 기본적으로 세 가지 클래스 로더가 제공됩니다.

  • 부트 스트랩 클래스 로더 : JAVA_HOME\lib에 있는 코어 자바 API를 제공합니다.
    최상위 우선순위를 가진 클래스 로더
  • 플랫폼(Extension) 클래스 로더 : JAVA_HOME\lib\ext 폴더 또는 java.ext.dirs 시스템 변수에
    해당하는 위치에 있는 클래스를 읽습니다.
  • 애플리케이션 클래스로더 : 애플리케이션 클래스 패스(애플리케이션 실행할 때 주는
    -classpath 옵션 또는 java.class.path 환경 변수의 값에 해당하는 위치)에서 클래스를 읽습니다.

메모리(Memory)

1. 메소드(Method) 

메소드 영역에는 클래스 수준의 정보들이 저장 및 공유하는 영역입니다.

예로 들어 클래스 이름, 클래스 멤버 변수 이름, 데이터 타입, 메소드의 이름, 리턴 타입, 파라미터, static변수 등이 생성됩니다.

2. 힙(Heap)

new 키워드로 생성된  객체(Instance)를 저장 및 공유하는 영역입니다.

메소드 영역에 로드된 클래스만 생성이 가능합니다.

 

힙이나 메소드는 모든 영역에 공유되는 자원입니다.

3. 스택(Stack)

스레드마다 생성이 되는 영역이고,

런타임 스택을 만들어 그 안에 메소드 호출을 스택 프레임이라 부르는 블록을 쌓습니다.

스레드가 종료되면 런타임 스택도 사라집니다.

메소드를 호출할 때마다 개별적으로 스택이 쌓입니다.

예로 들어 에러가 발생할 경우 위 사진처럼 메소드 호출 스택이 쌓여 보여 줍니다.

  

4. PC 레지스터(Program Counter Register)

스레드마다 생성이 되는 영역이고,

스레드가 현재 어떠한 명령 및 주소(스택 프레임)를 실행할 것인지를 가록 합니다.

참조 : https://javapapers.com/core-java/java-jvm-run-time-data-areas/#Program_Counter_PC_Register

5. 네이티브 메소드 스택(Native Method Stack)

스레드마다 생성이 되는 영역이고,

자바 외 언어로 작성된 네이티브 코드(주로 C, C++)를 수행하기 위한 스택(JNI) 영역입니다.

 

스택, PC레지스터, 네이티브 메소드 스택은 스레드마다 생성이 되고, 다른 스레드끼리 서로 공유되지는 않습니다.


실행 엔진(Execution Engine)

1. 인터프리터(Interpreter)

바이트코드를 한 줄씩 네이티브 코드로 변환하여  실행합니다.

2. JIT 컴파일러(JIT Compiler)

인터프리터 효율을 높이기 위해, 인터프리터가 반복되는 코드를 발견하면

JIT 컴파일로 반복되는 코드를 모두 네이티브 코드로 바꿔 둡니다.

그다음부터 인터프리터는 네이티브 코드로 컴파일된 코드를 바로 사용하게 됩니다.

3. 가비지 컬렉터(Garbage Collector)

힙 영역에 있는 더 이상 참조되지 않는 객체를 모아서 제거를 합니다.


JNI(Java Native Interface)

자바 애플리케이션에서 C, C++, 어셈블리로 작성된 함수를 사용할 수 있는 방법을 제공합니다.

Native 키워드를 사용한 메소드를 호출합니다.

스레드에서 대기시간을 설정하는 Thread.sleep() 메소드도 native 키워드를 사용하는 메소드입니다.

참조 : https://medium.com/@bschlining/a-simple-java-native-interface-jni-example-in-java-and-scala-68fdafe76f5f

 


네이티브 메소드 라이브러리(Native Method Library)

C, C++로 작성된 라이브러리입니다.

 

 

이로써 공부한 내용을 간략히 정리해보았습니다. 

감사합니다.

 


출처

https://www.inflearn.com/course/the-java-code-manipulation

https://jeong-pro.tistory.com/148

https://beststar-1.tistory.com/13?category=975450