본문 바로가기

Java

[JAVA] JVM(Java Virtual Machine)

1. JVM(Java Virtual Machine)이란?

자바 코드로 작성된 프로그램을 실행하면 이것을 컴퓨터가 이해할 수 있고, 어떤 운영체제에서도 실행 될 수 있는 기계어로 변환해주는 것이 바로 JVM이다.

즉 운영체제에 종속받지 않고 CPU가 자바 프로그램을 실행할 수 있는 환경을 만들어주는 소프트웨어라고 할 수 있다.

JVM은 또한 OS로부터 메모리를 할당 받고, Garbage Collectoion(사용하지 않는 메모리를 자동으로 회수)을 통해 자동으로 메모리 관리를 해준다는 특징을 가지고 있다.

이러한 JVM의 내부 구조와 동작 방식을 알면 성능 최적화나 리팩토링을 하는 데 매우 도움이 된다. 그렇다면 JVM은 어떤 방식으로 작동하여 Java 코드로 작성된 프로그램을 기계어로 변환하고 실행시키는 지 구체적으로 알아보도록 하자.


2. JVM의 동작 방식

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

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

3. Class Loader를 통해 필요한 클래스들을 JVM Runtime Data Area(JVM이 실행 중일 때 실질적으로 메모리를 할당받는 영역)로 로딩한다.

4. Runtime Data Area에 로딩 된 바이트 코드(.class)들은 실행엔진(Execution Engine)에 의해 해석된다.

5. 해석된 바이트 코드는 Runtime Data Area의 적절한 영역에 배치되어 실질적인 수행이 이루어진다. 이 과정에서 실행엔진(Execution Engine)에 의해 GC의 작동과 스레드 동기화가 필요에 따라 이루어진다.


3. JVM의 구조

JVM은 아래와 같이 구성되어 있다.

3-1) 클래스 로더(Class Loader)

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

  • PC Register 영역
  • Stack 영역
  • Heap 영역
  • Method 영역
  • Native Method Stack 영역

3- 3) 실행 엔진(Execution Engine)

  • 인터프리터(Interpreter)
  • JIT 컴파일러(Just-in-Time)
  • 가비지 콜렉터(Garbage Collector, GC)

3- 4) JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)

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


3-1) 클래스 로더(Class Loader)

컴파일 시점이 아니라 런타임 시점(.class 파일을 실행할 때=클래스를 처음으로 참조할 때)에 JVM 내로 필요한 클래스 파일(*.class)을 동적으로 로드하고, 링크를 통해 Runtime Data Area에 배치하는 작업을 수행하는 모듈이다.

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

  • Loading : 클래스를 읽어오는 과정
  • Linking : 참조와 실제 메모리 주소 값을 연결하는 과정
    • Verify: 로드된 ".class" 파일이 유효한 지 확인하는 과정
    • Prepare: 클래스나 인터페이스에 필요한 메모리를 할당하는 과정
    • Resolve: Loading단계에서 복사한 심볼릭 레퍼런스(symbolic reference) 값을 다이렉트 레퍼런스(direct reference)라는 메모리 주소 값으로 변경 (e.g. Book b = new Book();  //참조변수 b가 Heap에 저장된 Book의 메모리 주소를 참조하도록 연결하는 과정*)*
  • Initialization : java코드에서 선언한 static 변수와 static 메서드를 지정한 값들로 초기화 및 초기화 메서드를 실행시켜 주는 과정

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

 

JVM이 운영 체제 위에서 실행될 때, 할당 받는 메모리 영역으로 다음과 같이 분류된다.

  • Method 영역 : 모든 스레드가 공유하는 영역으로, 클래스 수준의 정보(클래스, 메서드 정보, 상수 풀 등)를 저장한다. Java 7까지는 Method Area가 Heap 내에서 Permanent Generation (PermGen)에 의해 관리되었으며, Java 8부터는 Native 메모리 영역으로 분리되며 Metaspace로 변경되었다. 다만, 정적 변수(Static Variables)는 Java 8부터 Heap 영역에서 관리된다.
  • Heap 영역 : 모든 스레드가 공유하는 영역(생성된 모든 객체와 배열이 저장되는 영역). Stack 영역과 다르게 보관되는 메모리의 호출이 끝나더라도 삭제되지 않고 유지된다. 그러다가 GC에 의해 더이상 참조되지 않는 객체는 제거된다.
  • Stack 영역 : 스레드마다 각각 존재. 스레드의 메소드 호출과 지역 변수 등을 관리
  • PC Register 영역 : 스레드마다 각각 존재. 스레드가 시작될 때 생성. 현재 실행중인 JVM 명령의 주소값을 가지며, 스레드 간의 컨텍스트 스위치가 발생할 때 이 레지스터를 적극 활용한다.
  • Native Method Stack 영역 : 자바가 아닌 언어로 작성된 네이티브 코드를 위한 메모리 영역

⇒ Method 영역, Heap 영역 : 모든 스레드에서 공유

⇒ 나머지 영역 : 스레드마다 각각 존재

 

+ Runtime Data Area에 관한 자세한 포스팅

 

[JAVA] JVM 메모리 구조(Runtime Data Area)

1. Runtime Data Area 구조 런타임 데이터 영역은 JVM의 메모리 영역으로 Java 애플리케이션을 실행 시 사용되는 데이터들을 동적으로 적재하는 영역이다.런타임 데이터 영역은 다음과 같이 크게 5가지

zisooya.tistory.com

 


 

3-3) 실행 엔진(Execution Engine)

클래스 로더에 의해 런타임 데이터 영역에 위치한 클래스 파일로부터 바이트 코드를 받고, 이것을 기계어로 변환하여 실제로 실행하는 역할을 한다. 이 때 실행 엔진이 바이트 코드를 기계어로 변환하고 실행하는 방식에는 크게 두 가지가 있다.

인터프리터(Interpreter)

바이트코드 명령어를 하나씩 읽어서 즉시 실행하는 방식. 빠르게 실행할 수 있지만, 같은 코드가 반복될 때마다 다시 해석해야 하므로 실행 속도가 느리다.

JIT 컴파일러(Just-in-Time)

JIT 컴파일러는 인터프리터의 단점을 극복하기 위해 도입되었다. 프로그램 실행 중에 바이트코드의 일부를 기계어로 변환하고, 변환된 코드를 캐시에 저장하여 재사용함으로써 성능을 향상시킨다. 이를 통해 반복 실행되는 코드의 속도를 크게 개선하지만, 컴파일 과정에서 일시적인 지연시간(Overhead)이 발생할 수 있다.

⇒ 초기 실행이나 덜 자주 사용되는 코드는 인터프리터에 의해 해석되어 실행되고, 자주 사용되는 코드는 JIT 컴파일러에 의해 기계어로 컴파일되고, 이후 실행 시에는 더 빠르게 처리되는 방식으로 JVM은 동작한다.

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

JVM은 Garbage Collector를 이용하여 Heap 메모리에서 더이상 사용되지 않는 메모리를 자동으로 회수한다. 개발자가 직접 메모리를 해제해주어야 하는 C언어와는 달리 Java는 이 가비지 컬렉터를 통해 자동으로 메모리를 실시간 최적화해주기 때문에 개발자에게 편의를 제공한다.

+ 가비지 콜렉터에 관한 자세한 포스팅

 

[JAVA] 가비지 콜렉션 (Garbage Collection, GC)

1. Garbage Collection(GC)이란?자바의 메모리 관리 방법 중의 하나로 JVM(자바 가상 머신)의 Heap 영역에서 동적으로 할당했던 메모리 중 참조되지 않는 객체를 모아 주기적으로 제거하는 프로세스를 말

zisooya.tistory.com

 


3-4) JNI - 네이티브 메소드 인터페이스 (Native Medthod Interface)

JNI는 자바가 다른 언어로 만들어진 어플리케이션과 상호 작용할 수 있는 인터페이스 제공하는 프로그램이다. JNI는 JVM이 Native Method Stack 영역에 적재되어 있는 자바가 아닌 언어로 작성된 네이티브 코드를 실행할 수 있도록 한다.


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

C, C++로 작성된 라이브러리를 칭한다.

JVM이 바이트 코드를 읽을 때, Native Call을 수행하는 코드가 있으면 JNI를 통해 이 라이브러리에서 Java code와 일치하는 native function을 로딩해 실행한다.