JVM(Java Virtual Machine)

JVM이란

자바 JVM(Java Virtual Machine)은 자바 언어로 작성된 코드를 실행하기 위한 가상 머신을 말한다. JVM은 자바 언어의 특징인 플랫폼 독립성을 가능하게 하고, 자바 코드를 실행하기 위해서 중요한 구성요소로 자리를 잡고 있다. 즉, JVM은 JAVA와 OS 사이에서 중개자 역할 수행하여 JAVA가 OS에 구애받지 않고 재사용을 가능케 한다. 그리고 가장 중요한 메모리 관리 및 Garbage Collection을 수행을 하고 있다. 

 

 가상머신(Virtual Machine)?
가상머신이란 프로그램을 실행하기 위해 물리적 머신과 유사한 머신을 소프트웨어로 구현한 것을 말한다.

 

# 자바프로그램 실행과정

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

 

http://asfirstalways.tistory.com/158


JVM 구성

# Class Loader(클래스 로더)

클래스 로더(Class Loader)는 Runtime시 동적으로 자바 클래스 파일을 읽어들이고, JVM이 사용할 수 있는 형태로 변화는 역할은 한다. 컴파일러는 jar 파일 내 저장된 클래스들을 JVM위에 탑재하고 사용하지 않는 클래들은 메모리에서 삭제한다. 

 

클래스로더는 로딩(Loading), 링크(Linking), 초기화(Initialization)라는 3단계로 이루어져 있다.

  1. 로딩(Loading) : 클래스 로더는 클래스 파일을 읽어 들인다.
  2. 링크(Linking) : 클래스 파일의 검증, 준비, 해석 작업을 수행한다. 
  3. 초기화(Initialization) : 클래스 변수(static) 변수 및 static 블록을 초기화 한다.

 

# Execution Engine(실행 엔진)

실행 엔진(Excution Engine)은 메모리에 저장된 바이트 코드를 실행하는 역할을 한다. 실행 엔진은 크게 인터프리터(Interpreter)와 JIT 컴파일러(Just - In - Time Compiler)로 구분된다. 

  1. 인터프리터(Interpreter) : 바이트 코드를 한 줄씩 읽어서 해석하고 실행한다. 
  2. JIT 컴파일러(Just - In - Time Compiler) : 인터프리터 방식으로 실행에서 야기 되는 성능 문제를 해결하기 위해, 바이트 코드를 네이티브 코드로 변경하고 더 이상 인터프리팅을 하지 하지 않고 실행한다. 네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일 된 코드는 빠르게 수행하게 된다. 물론 JIT 컴파일러가 컴파일하는 과정은 바이트코드를 인터프리팅하는 것보다 훨씬 오래 걸리므로 단 한번만 실행이 되는 코드라면 컴파일하지 않고 인터프리팅하는 것이 유리하다고 할 수 있다. 따라서 JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고, 일정 정도를 넘을 때에만 컴파일을 수행한다.  

 

네이티브 코드와 바이트 코드
네이티브 코드(Native Code)는 특정 프로세서 아키텍처에서 직접 실행할 수 있는 기계어 코드를 말한다. 이는 일반적으로 C/C++과 같은 네이티브 언어로 작성된 프로그램에서 생성된다. 네이티브 코드는 프로그램을 컴파일하여 생성된다. 컴파일러는 소스 코드를 분석하고 목적 코드를 생성한다. 목적 코드는 이진 형식으로 되어 있으며, 이는 CPU가 직접 실행할 수 있는 형태로 변환된다.

반면, 바이트코드(Bytecode)는 JVM이 실행할 수 있는 중간 언어 형식의 코드이다. 자바 컴파일러는 소스 코드를 바이트코드로 변환한다. 바이트코드는 특정 플랫폼에 종속되지 않는다는 특징을 가졌다. 즉, 한 번 작성된 바이트코드는 모든 플랫폼에서 동일하게 실행할 수 있다는 것이다. 바이트코드는 보통 .class 파일에 저장된다.

바이트코드는 자바 언어의 중간 언어로, 지금까지 설명을 해 왔듯이 자바 가상 머신(JVM)에서 실행된다. JVM은 바이트코드를 로드하고 상황에 따라 네이티브 코드로 변환하여 실행한다. 이러한 방식으로 JVM은 다양한 운영체제와 하드웨어에서 동일한 바이트코드를 실행할 수 있게 하고 있다.

 

# Garbage Collector

참조되고 있지 않은 객체들을 알아서 메모리에서 부터 삭제를 하는 역할을 한다. 해당 내용도 많은 내용을 포함하고 있어 다른 포스팅에서 자세하게 설명하도록 하겠습니다. 

 

JVM GC(Garbage Collection)

해당 글은 JVM에 대한 이해를 하고 읽으면 좋습니다. 이미 해당 블로그에는 JVM에 대한 설명을 해둔 글이 있으니 먼저 읽어보시고 해당 글을 읽어보는것을 추천합니다. JVM(Java Virtual Machine) JVM이란

jamesblog95.tistory.com


Runtime Data Area

자바 어플리케이션은 실행될 때, JVM은 어플리케이션의 코드를 실행하고 데이터를 저장할 수 있는 메모리 영역을 제공한다. 이를 Runtime Data Area 또는 JVM Memory 영역이라고 한다. 

http://asfirstalways.tistory.com/158

  • Method Area 메서드 영역은 클래스 파일을 로드하고 클래스별로 공유되는 정보를 저장하는 영역이다. 클래스 로더가 클래스 파일을 로드하면, 해당 클래스에 대한 정보가 Method Area에 저장된다. 이 정보에는 클래스 변수(static 변수), 메서드 코드, 메서드와 클래스의 Runtime 상수 풀 등이 포함된다. Method Area에 Runtime Constant Pool 이라는 별도의 관리 영역도 존재한다. 이는 상수 자료형을 저장하여 참조하고 중복을 맏는 역할을 수행한다. 
  • Stack Area 스택 영역은 각 Thread 별로 생성되며, 메서드 호출 시마다 해당 메서드의 지역 변수, 매개 변수, 리턴 값 등을 저장하는 영역입니다. 스택 영역은 메서드 호출이 끝나면 해당 메모리를 해제합니다.
  • PC Register PC(Register)는 현재 실행 중인 JVM 명령의 주소를 저장하는 영역입니다. 각 Thread 마다 별도로 저장됩니다.
  • Native Method Stack Native Method Stack 영역은 Java 이외의 언어(C, C++ 등)로 작성된 코드를 실행할 때 사용되는 스택 영역이다. Native Method Stack 영역은 JVM과 상호작용하는 네이티브 메서드를 호출할 때 사용됩니다.
  • Heap Area 힙 영역은 객체 인스턴스를 저장하는 메모리 영역이다. Heap 영역은 GC(Garbage Collector)가 수행되는 대상이며, 객체가 더 이상 사용되지 않으면 GC가 해당 객체를 제거하고 Heap 메모리를 회수한다. 

 

# Heap 영역

Heap 영역은 객체 인스턴스를 저장하는 메모리 영역으로, JVM이 실행되면서 자동으로 할당 및 관리된다. Heap 영역은 Java Virtual Machine이 실행되는 동안 메모리 공간이 필요할 때마다, 객체를 저장하기 위해 동적으로 할당된다.

 

Heap 영역의 크기는 -Xms와 -Xmx 옵션으로 조절할 수 있다. -Xms는 Heap 영역의 초기 크기를 설정하며, -Xmx는 Heap 영역의 최대 크기를 설정할 수 있다. 만약 Heap 영역의 크기가 부족하면 OutOfMemoryError가 발생한다.

 

Heap 영역은 Young Generation, Old Generation, PermGen 또는 Metaspace 영역으로 나뉘어진다.

  • Young Generation : Young Generation은 새로운 객체가 생성되는 영역이다. Young Generation은 다시 Eden 영역, S0(Survivor 0) 영역, S1(Survivor 1) 영역으로 나뉘어진다.
    • Eden 영역: 새로 생성된 객체가 저장되는 영역이다.
    • S0, S1 영역: Eden 영역에서 참조되는 객체들 중, 살아남은 객체들이 저장되는 영역입니다.
  • Old Generation : Old Generation은 Young Generation에서 살아남은 객체들이 저장되는 영역이다. Old Generation은 대개 큰 객체나 장기간 살아남는 객체들이 저장되며, Young Generation보다 큰 크기의 메모리 공간을 가진다.
  • PermGen 또는 Metaspace :  PermGen은 Java 7 이전에 사용되었던 메모리 영역으로, 클래스와 메서드, 상수풀 등의 메타데이터 정보를 저장합니다. Java 8부터는 PermGen 대신 Metaspace가 사용되며, 동적으로 크기를 조정할 수 있습니다.

Heap 영역에서 객체는 가비지 컬렉션(Garbage Collection, GC)에 의해 관리된다. JVM은 Heap 영역에서 더 이상 사용되지 않는 객체를 탐지하고 제거하며, 제거된 객체의 메모리 공간을 해제하여 Heap 영역을 유지한다. GC는 JVM에 내장되어 있으며, 자동으로 수행되며 개발자는 직접 메모리를 해제할 필요가 없다.

 

'Language > Java' 카테고리의 다른 글

객체 지향 프로그래밍(OOP)  (0) 2023.04.25
JVM GC(Garbage Collection)  (0) 2023.04.13
BigInteger, BigDecimal  (0) 2023.03.29
StringTokenizer, StringBuilder, StringBuffer  (0) 2023.03.27
정규식(Regular Expression)  (0) 2023.03.25