꾸물꾸물 졔의 개발공부

[CS/JAVA] JVM이란? 본문

CS

[CS/JAVA] JVM이란?

체제 2023. 8. 23. 18:01
JVM(Java Virtual Machine)이란? 

 

자바 가상 머신의 약자로 '자바를 실행하기 위한 가상 기계(컴퓨터)' 이다.

Java는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속받지 않고 어디서나 실행되기 위해선 OS 위에서 Java를 실행시킬 무언가가 필요하다. 그게 바로 JVM이다. 

즉, JVM은 OS에 종속받지 않고 CPU가 Java를 인식, 실행할 수 있게 하는 가상 컴퓨터이다.

 

 

우리가 작성한 Java 소스코드(.java)는 CPU가 인식하지 못하므로 기계어로 컴파일을 해주어야 한다. 

하지만 Java는 JVM을 거쳐서 OS에 도달하기 때문에 기계어로 바로 컴파일 되는 것이 아니라, JVM이 인식할 수 있는 Java bytecode(.class)로 변환된다. 

JVM은 OS와 Java 사이의 중개자 역할을 한다. JVM은 자바 바이트코드가 실행될 수 있는 환경을 제공해준다. 

 

변환된 bytecode는 기계어가 아니기 때문에 OS에서 바로 실행되지 않는다. 이 때, JVM이 OS가 bytecode를 이해할 수 있도록 해석해준다. 따라서 Byte Code는 JVM 위에서 OS 상관없이 실행될 수 있는 것이다. 

즉, JVM 덕분에 Java 파일 하나만 작성하면 OS에 상관없이 어디에서는 JAVA를 실행할 수 있다. 

 

 

컴파일 (Compile)

 

Java Compiler 가 .java 파일을 .class 라는 Java bytecode로 변환한다. 

 

Java Compiler는 JDK를 설치하면 javac.exe라는 실행 파일 형태로 설치된다. 정확히는 JDK의 bin 폴더에 javac.exe로 존재한다. 

Java Compiler의 javac 명령어를 사용하면 .java 파일을 컴파일하여 .class 파일을 생성할 수 있다. 

javac hello.java

 

 

실행 (Execute)

 

JDK 디렉토리의 /bin 폴더에 존재하는 java.exe 는 JVM을 구동시키기 위한 명령 프로그램이다. 

java 명령어로 컴파일 된 .class 파일을 실행 시킬 수 있다. 

java hello

.class 파일의 '이름'만 입력하면 된다. (hello.class)

 


JVM의 구성

 

JVM의 구성요소

 

JVM은 아래와 같이 이루어져 있다. 

  • 클래스 로더 (Class Loader)
  • 실행 엔진 (Execution Engine)
    - 인터프리터 (Interpreter)
    - JIT 컴파일러 (Just-in-Time)
    - 가비지 콜렉터 (Garbage Collector)
  • 런타임 데이터 영역 (Runtime Data Area) 

 

JVM을 기반으로 한 대략적인 자바프로그램의 실행과정은 다음과 같다. 

1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받는다. (JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리한다.) 
2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킨다.
3. Class Loader를 통해 class 파일들을 JVM으로 로딩한다.
4. 로딩된 class 파일들은 Execution engine을 통해 해석된다.
5. 해석된 바이트코드는 Runtime Data Areas에 배치되어 실질적인 수행이 이루어지게 된다.
이러한 실행과정 속에서 JVM은 필요에 따라 Thread Synchronization과 GC 같은 관리작업을 수행한다.  

 

 

Class Loader (클래스 로더)
JVM 내로 클래스 파일(.class)을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다. Runtime 시점에 클래스를 동적으로 로딩하고, 클래스의 인스턴스를 생성하면 클래스 로더를 통해 메모리에 로드하게 된다. 
Execution Engine (실행 엔진) 
앞서 로드된 클래스의 바이트코드를 실행시키는 모듈이다. 
클래스 로더를 통해 JVM 내의 Runtime Data Area (런타임 데이터 영역)에 배치된 바이트코드는 실행 엔진에 의해 실행되며, 자바 바이트 코드는(.class) 기계가 바로 수행할 수 있는 언어가 아니다. 그래서 실행 엔진은 이와 같은 자바 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경하는데, 이때 Interpreter 방식과 JIT 방식을 사용하게 된다. 

💡Interpreter (인터프리터)
인터프리터는 프로그래밍 언어의 소스 코드를 바로 실행하는 프로그램을 말한다. 원시코드를 기계어로 번역하는 컴파일러와 대비된다. 실행엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행한다. 하지만 한 줄씩 수행하기 때문에 수행 속도가 느리다는 단점이 있다. 
💡JIT Compiler (Just In Time) 
인터프리터 방식의 단점을 보완하기 위해 도입되었다. JIT 컴파일러는 바이트코드를 컴파일하여 native code(네이티브 코드)로 변환하여 사용한다. 즉 한 번 컴파일된 코드는 빠르게 수행되어 속도가 빠르다. 하지만 컴파일하는 과정에 비용이 든다. 따라서 한 번만 수행할 코드라면 굳이 컴파일하지 않고 인터프리팅 하는 것이 더 유리하다. JVM은 인터프리터 방식으로 실행하다가 적절 기준이 넘어가면 JIT 컴파일러를 사용해서 기계어로 직접 실행하는 혼합 방식을 사용한다. 
Garbage Collector (가비지 콜렉터)
더 이상 사용되지 않는 인스턴스를 찾아 메모리에서 삭제.

 

Runtime Data Area

 

Runtime Data Area

Runtime Data Area는 JVM이 프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간이다. Runtime Data Area는 크게 5가지 영역으로 나눌 수 있다. 

 

1. PC Register

Thread가 시작될 때 생성되며 각 스레드마다 하나씩 존재한다. Thread가 어떤 부분을 어떤 명령으로 실행해야 할 지에 대한 기록을 하는 부분으로 현재 수행 중인 JVM 명령의 주소를 갖는다. 

 

2. JVM Stack 

각종 형태의 변수나 임시 데이터, 스레드나 메소드의 정보를 저장한다. 

메소드(method)가 호출될 때 메소드와 메소드의 정보는 JVM Stack 에 쌓이게 된다. 즉, 메소드의 매개변수 (parameter), 지역 변수 (local variable), return 주소, 임시 변수 등의 정보를 기록하는 스택이다. 각 스레드 별로 생성되기 때문에 다른 스레드는 접근할 수 없다. 메서드 호출이 종료되면 스택에서 정보들이 제거된다. 

 

3. Native Method Stack 

Java가 아닌 다른 언어로 작성된 네이티브 코드를 위한 공간이다. Java Native Interface를 통해 바이트 코드로 전환하여 저장하고 수행한다.

 

4. Method Area (=Class Area =Static Area) 

모든 쓰레드가 공유하는 메모리 영역. 클래스, 인터페이스, 메서드, 필드, Static 변수 등의 바이트 코드를 보관한다. Method Area에는 Runtime Constant Pool이라는 별도의 관리영역도 존재하는데, 이는 상수 자료형을 저장하고 참조하여 중복을 막는 역할을 수행한다. 

 

5. Heap

Heap 영역

Runtime 시점에 동적으로 할당하여 사용하는 영역이다. 객체를 저장하는 가상메모리 공간으로, 클래스를 이용해 인스턴스를 생성하면 Heap에 저장된다. 즉, new 연산자를 이용해 생성된 객체를 저장하는 영역이다. Class Area에 올라온 클래스들만 객체로 생성할 수 있다. 

Heap은 크게 New/Young 영역, Old 영역, Permanent Generation 3영역으로 나뉘어진다. 

 

Permanent Generation

말 그대로 영구적인 세대이다. 생성된 객체들의 정보와 주소값이 저장되는 공간이다. 클래스 로더에 의해 로드되는 Class, Method 등에 대한 Meta 정보가 저장되는 영역이고 JVM에 의해 사용된다.

 

New/Young 영역

이곳의 인스턴스들은 추후 가비지 콜렉터에 의해 사라진다. 생명 주기가 짧은 '젊은 객체'를 GC 대상으로 하는 영역이다. 여기서 일어나는 가비지 콜렉터를 Minor GC 라고 한다. 

 

Old 영역

이곳의 인스턴스들은 추후 가비지 콜렉터에 의해 사라진다. 생명 주기가 긴 “오래된 객체”를 GC 대상으로 하는 영역이다.

여기서 일어나는 가비지 콜렉터를 Major GC라고 하며, Minor GC에 비해 속도가 느린 편이다. 

New/Young 영역에서 일정시간 참조되고 있는, 살아남은 객체들이 저장되는 공간이다.