JVM에 대하여

띠로리·2022년 8월 23일

JVM은 바이트 코드를 해석해 OS 위에서 실행하는 것은 물론, 메모리 관리와 Garbage Collection 까지 포함하고 있는 아주 기본적이면서도 중요한 부분이다. 동일한 기능의 프로그램이더라도 JVM의 메모리 관리를 어떻게 하느냐에 따라 성능이 좌우될 수 있으므로 JVM에 대한 개념은 꼭 알아두자.


먼저 JVM이 전체적으로 어떻게 구성되어 있는지 알아보자.

JVM의 구성요소

JVM은 크게 아래와 같이 3 부분으로 이루어져 있다.

  • 클래스 로더 (Class Loader)
  • 실행 엔진 (Execution Engine)
    • 인터프리터 (Interpreter)
    • JIT Compiler (Just-In-Time)
    • 가비지 콜렉터 (Garbage Collector)
  • 런타임 영역 (Runtime Data Areas)
    • PC Register
    • Stack
    • Native Stack
    • Method Area (=Static Area)
    • Heap

클래스 로더 (Class Loader)

자바 클래스들은 어플리케이션 실행 시 한 번에 로드되지 않고, 어플리케이션이 실행되다가 클래스 파일을 참조하는 순간 동적으로 읽어서 메모리에 로드되면서 JVM에 링크된다.

실행 엔진 (Execution Engine)

바이트 코드를 JVM 내부에서 기계어로 번역하는 역할을 주로 맡는다. 실행 엔진 영역은 다시 3부분으로 나뉘어진다.

1. 인터프리터 (Interpreter)

런타임 시 명령어 단위로 바이트코드를 기계어로 해석하는 번역 프로그램이다.

2. JIT Compiler (Just-In-Time)

프로그램 실행 초기에 인터프리터에 의해 코드가 실행되고 자주 사용되는 코드는 JIT Compiler에 의해 컴파일 된다. 이렇게 컴파일 된 코드를 네이티브 코드라고 하는데, 네이티브 코드는 캐시에 보관되기 때문에 같은 함수가 여러 번 불릴 때 매번 해석되는 것을 방지한다.
이 JIT Compiler는 JVM의 성능에 가장 큰 영향을 준다고 볼 수 있다.

3. Garbage Collector

더 이상 참조되지 않는 객체들을 아래에서 설명할 heap 영역 메모리에서 삭제한다. (자세한 설명을 다음 글에 하겠다.)

런타임 영역 (Runtime Data Areas)

프로그램을 수행하기 위해 OS에서 할당받은 영역이다. 이 구간은 다시 5 부분으로 나뉘어진다.

PC Register와 Stack, Native Stack은 Thread 별로 독립적인 공간이 존재하고, Heap, Static Area는 공유한다.
멀티 쓰레드 프로세스의 경우 공유되는 메모리 데이터에 대해 간섭하는 경우가 있을 수 있다.
이를 '동기화(Synchronized)' 작업을 통해 막아준다.
(자바에서는 Synchronized 라는 키워드를 통해 해결한다.)

1. PC Register

Thread가 시작될 때마다 생성되는 공간으로, Thread가 어떤 명령을 실행하게 될지 명령 주소를 저장하는 공간이다.

2. Stack

프로그램 실행 과정에서 임시로 할당되었다가 메서드를 빠져나가면 바로 소멸되는 특징의 데이터를 저장하기 위한 영역이다.
예를 들면 매개변수, 지역변수, 리턴 값, 연산 시 일어나는 값들을 임시로 저장한다.
이 때, 참조형 타입 변수는 참조 주소값만 저장된다. 이 참조값은 heap 영역에 존재하는 인스턴스를 가리키는 역할을 한다.

3. Native Stack

자바 외 언어로 작성된 네이티브 코드를 위한 영역이다.

4. Methid Area (=Static Area)

클래스 정보를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 메모리 공간이다.
static 키워드가 붙은 필드와 메서드, 패키지나 클래스 정보 등이 저장된다.
이 영역에 자리잡게 되면 JVM이 종료될 때까지 사라지지 않는다.

5. Heap

new 연산자로 생성되는 객체와 배열을 저장하는 영역이다.
당연한 얘기겠지만 Static Area에 올라온 클래스만 이 영역에 저장될 수 있다.
만약 어떤 참조변수도 이 영역에 있는 인스턴스를 참조하지 않는다면 gc에 의해 메모리에서 삭제되게 된다.


동작 과정

JVM의 동작과정은 다음과 같다.

  1. 프로그램이 실행되면 JVM은 OS로 부터 필요한 메모리를 할당받는다.
  2. JVM의 'Class Loader' 를 통해 바이트코드(class 파일)를 JVM으로 로딩한다.
  3. 로딩된 파일들은 Execution Engine을 통해 해석된다.
  4. 해석된 바이트 코드들은 Runtime Data Areas 에 배치되어 프로그램이 수행된다.
  5. 프로그램이 실행되며 JVM은 필요에 따라 Tread Synchronization 이나 gc와 같은 관리작업을 수행한다.
profile
꼼퓨타

0개의 댓글