CS/Java

JVM (Java Virtual Machine)

leah-only 2025. 3. 13. 19:51

JVM 이란? 

 자바 가상 머신(Java Virtual Machine)의 약자로, 컴퓨터가 자바 바이트 코드를 운영체제에 맞게 실행시키는 역할을 수행합니다.

JVM은 OS의 종류에 상관없이 자바 파일을 실행할 수 있도록 중개자 역할을 합니다. 따라서 자바는 플랫폼 독립적 특성을 가집니다.


JVM의 작동 방식

 

1️⃣ 자바 프로그램을 실행하면 JVM은 OS로부터 메모리를 할당받는다.

2️⃣ 자바 컴파일러(javac)가 자바 소스코드(.java)를 자바 바이트 코드(.class)로 컴파일한다.

3️⃣ Class Loader를 통해 필요한 클래스들을 로딩 및 링크하여 Runtime Data Area에 올린다.

4️⃣ Runtime Data Area에 로딩된 .class 들은 Execution Engine을 통해 해석된다. 

5️⃣ 해석된 바이트 코드는 Runtime Data Area의 각 영역에 배치되어 수행하며 이 과정에서 Execution Engine에 의해 Garbage Collector의 작동과 Thread 동기화가 이루어진다. 


JVM 구조 


클래스 로더 (Class Loader)

자바 컴파일러가 .java 파일을 컴파일하여 .class파일(바이트 코드)이 생성되면 이 생성된 클래스 파일들을 엮어 JVM의 메모리 영역인 Runtime Data Area로 적재하는 역할을 한다. 

클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 어플리케이션에서 필요한 경우 동적으로 메모리에 적재하게 된다.

클래스 파일의 로딩 순서는 다음과 같이 3단계로 구성된다. (Loading → Linking → Initialization)

 

적재 (Loading)

  • 컴파일된 클래스를 메모리에 적재
  • Loading의 작업은 보통 static main() 메서드로부터 시작된다. 
  • 이미 로딩된 클래스는 upload 될 수 없다. 

연결 (Linking)

  • 클래스 파일을 사용하기 위해 검증하는 과정
    • Verifying(검증) : 읽어들인 클래스가 JVM 명세에 명시된 대로 구성되었는지 검사
    • Preparing(준비) : 메모리 할당
    • Resolving(분석/실행) : 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경. 즉, 실제 객체의 주소를 참조

초기화 (Initialize)

  • 클래스 변수들을 적절한 값으로 초기화 
  • static 필드들을 설정된 값으로 초기화 등

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

JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역

모든 스레드에서 공유하는 영역

Method Area

  • 클래스 구조 & 정적 필드(코드, 변수, static, final 변수 등)를 저장한다. 
  • JVM 시작 시 생성되고 프로그램 종료 시까지 저장된다. 
Runtime Constant Pool
메서드 영역에서 존재하는 별도의 관리 영역
상수 자료형을 저장하여 참조하고 중복을 막는 역할 수행

 

Heap Area

  • new 키워드로 생성한 객체가 저장되는 영역 (동적으로 생성된 객체와 배열이 저장되는 곳)
  • Garbage Collection의 대상이 되는 영역 (주기적으로 GC가 제거하는 영역)

☑️ Young Generation : 새로 생성된 객체들이 할당되는 영역

  • 객체를 최초 생성하면 Young 영역의 Eden 영역에 할당된다.
  • Eden 영역에 데이터가 어느정도 쌓이에 되면 참조 정도에 따라 Survivor의 빈공간으로 이동 or 회수
  • Young 영역이 차게 되면 참조 정도에 따라 Tenured Generation(Old) 영역으로 이동되거나 회수
  • Young 영역이 꽉 차면 Minor CG가 발생 (Eden 영역 차면 Minor CG 발생하여 Survivor으로 이동 or 회수)

☑️ Tenured Generation : Young Generation에서 오래 살아남은 객체들이 이동하는 영역

  • 이 영역이 꽉 차면 Major GC가 발생
  • Major GC가 발생했을 때, 참조 여부에 따라 유지되거나 제거된다. 

각 스레드별로 생성

Stack Area

  • 지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역
  • 동적으로 객체를 생성하면 실제 객체는 Heap에 할당되고 해당 레퍼런스만 stack에 저장된다.
  • Heap에 있는 객체가 Stack에서 참조할 수 없는 경우 GC의 대상이 된다.

PC Register

  • 스레드 별로 생성되는 영역
  • 현재 스레드가 실행되는 부분의 주소와 명령을 저장하고 있다. 

Native Method Stack 

  • 자바 외 언어로 작성된 네이티브 코드를 위한 메모리 영역

 

실행 엔진 (Execution Engine)

런타임 데이터 영역에 배치된 바이트 코드를 명령어 단위로 읽어서 실행한다. 

자바 바이트 코드(.class)는 기계가 바로 수행할 수 있는 언어보다는 가상 머신이 이해할 수 있는 중간 레벨로 컴파일 된 코드이다. 그래서 실행 엔진은 이와 같은 바이트 코드를 실제로 JVM 내부에서 기계가 실행할 수 있는 형태로 변경해준다. 

 

이 과정에서 실행 엔진은 인터프리터와 JIT 컴파일러 2가지 방식을 혼합하여 바이트 코드를 실행한다. 

 

인터프리터 (Interpreter)

바이트 코드 명령어를 하나씩 읽어서 해석하고 바로 실행

JVM 안에서 바이트 코드는 기본적으로 인터프리터 방식으로 동작한다. 

속도가 느리다는 단점이 존

 

JIT 컴파일러

위의 인터프리터의 단점을 보완하기 위해 도입된 방식으로 반복되는 코드를 발견하여 바이트 코드 전체를 컴파일하여 Native Code로 변경하고 네이티브 코드로 직접 실행하는 방식


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

GC를 이용하여 Heap 메모리 영역에서 더는 사용하지 않는 메모리를 자동으로 회수한다. 

C언어 같은 경우 직접 개발자가 메모리를 해제해줘야 되지만, JAVA는 GC를 이용해 자동으로 메모리를 실시간 최적화 시켜준다. 따라서 개발자가 따로 메모리를 관리하지 않아도 되므로 더욱 손쉽게 프로그래밍 할 수 있도록 해준다. 

 

일반적으로 자동으로 실행되지만, GC가 실행되는 시간은 정해져 있지 않다. 

특히 Full GC가 발생하는 경우 GC를 제외한 모든 스레드가 중지되기 때문에 장애가 발생할 수 있다. 

 

GC 동작방식

☑️Stop The World

  • GC를 실행하는 스레드를 제외한 모든 스레드는 작업이 중단되고, GC가 완료되면 작업을 재개
  • 모든 스레드의 작업이 중단되면 애플리케이션이 멈추기 때문에 GC 성능 개선을 위해 튜닝 시 stop the world 시간을 줄이는 작업을 보통 수행

☑️Mark and Sweep

  • Mark : 사용되는 메모리와 사용되지 않는 메모리를 식별하는 작업
  • Sweep : Mark 단계에서 사용되지 않음으로 식별된 메모리를 해제하는 작업

☑️Compact

  • 객체들을 가까운 곳으로 모으고 heap 메모리의 아래쪽으로 보냄
  • 바로 옆에 할당된 객체라고 해서 같은 시점에서 메모리에서 해제되리라는 법은 없음 -> 메모리가  GC를 거쳐 파편화 될 수 있음
  • 파편화를 최소화하기 위해서 JVM은 Major GC 때마다 Generation에 Compaction을 수행 

 

어떻게 사용하지 않는다고 판단하고 제거가 될까? 

객체는 힙 영역에 저장되고 스택 영역에 이를 가르키는 주소값이 저장되는데 

힙 영역에서 자신을 가르키는 주소값이 없으면 참고되고 있지 않는다고 판단한다. 

  • GC가 동작을 하면 GC Root로부터 객체를 찾고, 그 객체가 참조하는 객체를 찾아 mark한다.
  • Mark 되지 않은 객체는 접근할 수 없다고 판단하여 제거된다. ( = sweep)

참고 : https://thalals.tistory.com/314

https://inpa.tistory.com/entry/JAVA-%E2%98%95-JVM-%EB%82%B4%EB%B6%80-%EA%B5%AC%EC%A1%B0-%EB%A9%94%EB%AA%A8%EB%A6%AC-%EC%98%81%EC%97%AD-%EC%8B%AC%ED%99%94%ED%8E%B8

https://github.com/devFancy/2023-CS-Study/blob/main/java/java_jvm_architecture.md

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

Call by Value & Call by Reference  (0) 2025.03.24
Xms, Xmx  (0) 2025.03.21
JDK / JRE  (0) 2025.03.21
객체 지향 프로그래밍 (Object-Oriented Programming, OOP)  (1) 2025.03.12
Java Build Tool - Gradle/Maven  (1) 2025.03.11