[CS] JVM이란?

허석진·2024년 7월 10일

CS

목록 보기
1/3
post-thumbnail

참고 자료

JVM (Java Virtual Machine)이란?

Java(또는 Kotlin)라는 언어를 해당 OS가 이해할 수 있는 언어로 변환하는 번역기라고 생각하면 편할 것 같다.
그 이유는 OS마다 System call이, 사용하고 있는 기기의 CPU마다 명령어 세트가 다르기 때문이다.

때문에 아래와 같이 운영체제따라, CPU에 따라 설치해야할 JVM이 다른 것이다.
(아래 사진은 JDK지만 JDK가 JVM을 포함하고 있다는 점을 감안해주길 바란다.)
JDK downloads

따라서 독립적이라는 뜻은, 우리가 작성하는 Java 코드가 위에 같은 조건에 독립적이라는 뜻이고, 우리는 항상 Java라는 언어를 사용하고, 각 기기에는 그에 맞는 Java 번역기(JVM)를 설치해서 사용하는 것이다.

그럼 이것이 어떻게 가능할까?

코드 변환 과정

java code translation

  1. *.java을 javac를 통해 컴파일하면 *.class(byte code)로 변환된다.
    • *.class 파일은 아직 사람이 읽을 수 있는 코드 정도의 파일이다.
    • 이는 intellij 기준, build 폴더에서 찾아볼 수 있으며, 기존 코드를 살짝 변형한 정도의 변환이다.
  2. *.class를 통해 Java Application을 실행하면, JVM에 Process가 생성되고, 이를 JVM 내부에 있는 Interpreter와 JIT compiler가 Native Machine Language(binary code)로 번역한다.
  3. JVM Process는 넘겨받은 *.class(byte code)와 번역된 Native Machine Language(binary code)를 Process의 메모리 공간 내부에 저장하게 되는 것이다.
    이런 저장된 공간은 Run Time Data Area라고 하며, 이런 일이 일어나는 공간은 당연 RAM이다.

JVM의 구성

JVM이 대략 어떻게 작동하는지 알았으니, 다음으로 자세한 설명으로 넘어갈 차례이다.
해당 파트에서는 JVM을 구성하고 있는 요소들에 대해 설명해보겠다. (JVM 상자 내부에 것들)
전체 흐름 구성도

Class Loader (클래스 로더)

Class loader는 Java Class File 형식에 부합하는 모든 것을 인식하고 JVM Process 메모리 공간에 로드하는 유닛이다.
(구현에 따라 다른 Binary 형식도 인식할 수 있지만, 최소 Class File 만은 반드시 인식한다.)

Class loader는 다음 순서를 지키며 작업을 실행한다.

  • Loading: Type에 대한 Binary data를 찾고 가져옵니다.
  • Linking: 다음 2가지를 수행한다.
    • Verification: 가져온 Type이 올바른지 확인한다.
    • Preparation: Class 변수에 메모리를 할당하고 기본 값으로 초기화한다.
  • Initialization: Class 변수를 올바른 초기 값으로 설정하는 Java 코드를 호출한다.

Execution

코드를 해석(byte to binary)과 메모리 관리를 담당하는 유닛이다.

Interperter (인터프리터)

Byte code를 읽음과 동시에 번역하는 번역기다.
하지만, 이런 번역은 당연히 실행 시간에 영향을 줄 수 밖에 없다.

이를 해결하기 위해 JIT Compiler가 존재한다.

JIT Compiler (JIT Compiler)

프로그램이 실행되는 도중에 실행되는 번역기다. (그래서 Just in time, JIT이다.)
이 Compiler는 주로 자주 실행되는 코드에 적용되어, 해당 코드를 Byte code로 미리 번역해둔다.
이런 작업은, 전체 실행 시간을 크게 단축시켜준다.

Garbage Collector (GC, 가비지 컬렉터)

사용되지 않는 인스턴스를 찾아 메모리에서 제거하여 메모리 공간을 확보하는 역할을 한다.
이는 단순히 잘 사용 안한다고 제거해버리는게 아니라, 해당 구현에 정해져있는 정책을 따르는데, GC는 Java 버전별로 여러 구현을 가지고 있다.

Runtime Data Area (런타임 데이터 영역)

Rumtime Data Area 구성

해당 예시는 1개의 프로세스에서 3개의 Thread(Main Thread 포함)를 실행했을 때의 모습이다.

PC Register (Program Counter Register, PC 레지스터)

다음에 실행할 명령어의 주소를 저장하는 Register이다.
일반적으로 OS에서 모든 Thread는 CPU를 독점하지 않고 번갈아 사용하도록 되어 있으므로, Thread마다 PC Register를 가지고 되는 것이다.

JVM Stack (JVM 스택)

프로그램 실행과정에서 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다.

사실 이 부분은 JVM 설명에서 자세히 설명할만한 부분은 아니고, 이에 대해 자세한 내용은 구글에 stack memory, heap memory를 검색해보는 것을 추천한다.

Native Method Stack (네이티브 메서드 스택)

Java 이외의 언어로 작성된 메서드(Native Method)를 지원하기 위해 존재하는 Stack이다.
이를 사용하지 않는 JVM을 구현한다면 제외되는 영역이다.

Method Area (메서드 영역)

JVM이 시작될 때 생성되며, JVM의 모든 Thread가 공유하는 영역이다.
OS Process의 텍스트 영역과 유사한 역할을 하며, Runtime Constant Pool, 필드 그리고 메서드 데이터, 메서드 및 생성자의 코드와 같은 Class 별 구조가 저장된다.

이 영역은 논리적로 Heap 일부로 간주되지만, JVM 구현에 따라 해당 영역에 대한 Garbage Collecting 여부를 결정할 수 있다.

Runtime Constant Pool (런타임 상수 풀)

Class file에 있는 constant_pool table의 Class별 또는 Interface별 Runtime식 표현이다.
이는 여러 상수를 포함하는데, Compile 시점에 알려진 숫자(Numeric Literal)들 부터 Runtime 시점에서 해결해야되는 메서드 및 필드 참조에 이르기까지 다양한 종류의 상수가 포함된다.

Runtime Constant Pool은 전통적인 프로그래밍 언어의 Symbol Table과 유사한 기능을 수행하지만, 일반적으로 보다 더 넓은 범위의 데이터를 포함한다.

Heap (힙)

Heap
Method Area와 동일하게, JVM이 시작될 때 생성되며, JVM의 모든 Thread가 공유하는 영역이다.
또한, Heap은 모든 Class의 인스턴스와 배열에 대한 메모리가 할당되는 Runtime Data Area이라고도 할 수 있다.

해당 영역은 GC라는 자동 저장 관리 시스템에 의해 관리되는데, 위에서 언급했듯이, 자동방식은 구현에 따른다.
Java 17 버전 GC

JVM - JRE - JDK 차이

JVM - JRE - JDK

위에 그림 1장으로 대부분의 설명을 할 수 있다.

JRE (Java Runtime Environment)

JRE는 말 그대로 JVM에 실행하는데 필요한 라이브러리들을 포함한 Java를 실행시킬 수 있는 환경이다.
이것 없이 Java를 실행하려하면, JRE를 설치하라는 알림이 뜨는 프로그램이 종종있다. (필자의 경우, 어린 시절 Minecraft Java 버전이 그랬다.)

JDK (Java Development Kit)

JDK는 JRE에다가 개발에 필요한 툴들을 추가로 포함시킨 것이다.
예를들어 javac(Java Compiler), jdb(Java Debugger), javadoc 등이 있다.

회고

이것보다 훨씬 가볍게 정리하려고 시작한 글이였다...
그런데, 다른 분들의 블로그를 참고하면서, "Byte code는 Binary code가 되어 실행된다는데, 그럼 대체 어디에 저장이 되는걸까?", "JVM이랑 운영체제 과목에서 배웠던 Process는 무슨 관계지?"라는 의문이 계속 들더니 결국 좀 딥하게 들어가는 글이 되어버렸다 ㅎ..

하지만 나름 궁금한 점들을 많이 해결했고 그만큼 기억에도 남을 것 같아 만족!

0개의 댓글