본문 바로가기
공부 자료/Java

[Java] JVM

by 미노킴 2022. 11. 27.

JVM에 관해 공부한 내용들을 정리해 보았다.

1. JVM 이란?

자바 가상 머신 JVM(Java Virtual Machine)은 자바 프로그램 실행환경을 만들어 주는 소프트웨어이다. 우리가 작성하는 소스 코드(.java)는 java compiler를 통해 자바 바이트 코드(.class)로 변환 되고, 이 바이트 코드를 JVM이 바이너리 코드로 변환시켜 OS에 전달해준다. 바이너리 코드는 컴퓨터가 인식할 수 있는 0과 1로 구성된 이진 코드이다.

 

JVM 덕분에 자바의 소스 코드는 OS에 종속적이지 않다. 각 OS별로 해당 OS에 맞는 JVM만 설치되어 있다면 우리는 동일한 소스 코드를 윈도우, 리눅스, 맥 OS 그리고 다른 운영체제에서도 사용할 수 있다.

JVM의 코드 해석 방식

JVM은 바이트 코드를 해석할 때 Interpreter 방식JIT 컴파일 방식을 혼합하여 사용한다. Interpreter 방식은 초기 방식으로 바이트 코드를 한 줄씩 해석하고 실행하여 속도가 느리다는 단점이 있다. 이 단점을 보완하기 위해 나온 것이 JIT 컴파일 방식이다. JIT 컴파일 방식은 JIT 컴파일러를 이용해 같은 코드를 매번 해석하지 않고 코드를 실행할 때 모든 코드를 한번에 각 OS에 맞는 Native Code로 변환한다. 그리고 해당 코드들을 캐싱하여 이후 같은 코드가 들어오면 캐싱된 코드를 사용하고 바뀐 부분만 컴파일을 진행한다. 다만 Native Code로 변환하는 데에도 비용이 소모되므로 Interpreter 방식을 사용하다가 일정 기준이 넘어가면 JIT 컴파일 방식으로 명령어를 실행한다. 

2. JVM의 내부 구조와 동작 방식

JVM 내부 구조

JVM의 동작 방식은 다음과 같다.

 

1. 소스 코드를 실행하면 JVM은 OS로부터 메모리를 할당받는다.

2. 자바 컴파일러가 자바 소스 코드를 자바 바이트 코드로 컴파일한다.

3. 바이트 코드를 Class Loader를 통해 JVM Runtime Data Area로 로딩한다.

4. Runtime Data Area에 로딩 된 바이트 코드를 Execution Engine을 통해 해석한다.

5. 해석된 바이트 코드는 Runtime Data Area의 각 영역에 배치되며 이 과정에서 Execution Engine에 의해 가비지 컬렉터(GC)가 작동하고 스레드 동기화가 이루어진다.

클래스 로더 (Class Loader)

자바는 동적 로드를 진행하는데, 동적 로드는 컴파일 타임이 아니라 런타임(바이트 코드를 실행할 때)에 클래스를 로드하고 링크하는 것을 말한다. 이 동적 로드를 담당하는 것이 클래스 로더이다. 클래스 로더는 로딩, 링크, 초기화 단계로 나누어 동적 로드를 진행한다.

 

로딩 단계에선 자바 바이트 코드를 메소드 영역에 저장한다. 그리고 바이트 코드는 매모스 영역에 다음의 내용들을 저장한다.

- 로드된 클래스를 비롯한 그의 부모 클래스의 정보

- 클래스 파일과 클래스, 인터페이스, Enum 관련 여부

- 변수나 메소드 등의 정보

 

링크 단계에선 읽어 들인 클래스가 자바 언어 명세 및 JVM 명세에 명시된 대로 잘 구성되어 있는지 확인한다. 그 후 클래스가 필요로 하는 메모리를 할당하고 클래스에서 정의된 필드, 메소드, 인터페이스를 나타내는 데이터 구조를 준비한다. 마지막으로 심볼릭 메모리 레퍼런스를 메소드 영역에 있는 실제 레퍼런스로 교체한다.

 

초기화 단계에선 클래스 변수들을 적절한 값으로 초기화 한다.

실행 엔진 (Execution Engine)

로드된 바이트 코드를 실행하는 런타임 모듈이다. 실행 엔진은 바이트 코드를 명령어 단위로 읽어서 실행한다.

가비지 컬렉터 (Garbage Collector)

가비지 컬렉터는 Heap 메모리 영역에 생성된 객체들 중 참조되지 않은 객체들을 탐색한 후 제거한다. 가비지 컬렉터 역할을 수행하는 스레드를 제외한 나머지 모든 스레드들은 일시정지 상태가 된다. 가비지 컬렉터 덕분에 Java에서는 개발자가 메모리 영역에서 사용되지 않는 객체를 따로 관리할 필요가 없다.

 

 

자바 가상 머신은 가비지 컬렉터(garbage collector)를 이용하여 더는 사용하지 않는 메모리를 자동으로 회수해 줍니다. 따라서 개발자가 따로 메모리를 관리하지 않아도 되므로, 더욱 손쉽게 프로그래밍을 할 수 있도록 도와줍니다. Heap 메모리 영역에 생성(적재)된 객체들 중에 참조되지 않은 객체들을 탐색 후 제거하는 역할을 하며 해당 역할을 하는 시간은 정확히 언제인지를 알 수 없습니다. GC역할을 수행하는 스레드를 제외한 나머지 모든 스레드들은 일시정지상태가 됩니다.

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

런타임 데이터 영역은 JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 저장해두는 영역이다.

 

모든 스레드가 공유해서 사용 (GC의 대상)

  • 힙 영역 (Heap Area)
  • 메서드 영역(Method Area)

 

스레드(Thread) 마다 하나씩 생성

  • 스택 영역(Stack Area)
  • PC 레지스터 (PC Register)
  • 네이티브 메서드 스택(Native Method Stack)

 

메서드 영역 (Method Area)

클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보와 같은 각종 필드 정보들과 메서드 정보, 데이터 Type 정보, Constant Pool, static변수, final class 등이 생성되는 영역이다.

 

힙 영역 (Heap Area)

new 키워드로 생성된 객체와 배열이 저장되는 영역이다.

 

스택 영역 (Stack Area)

지역변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값 등이 생성되는 영역이다.

 

PC 레지스터 (PC Register)

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

 

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

자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행할 때 사용되는 메모리 영역으로 일반적인 C 스택을 사용한다.