JAVA JVM(JAVA Virtual Machine)

JAVA JVM(JAVA Virtual Machine)

Posted by dydtjr1128 on October 08, 2019 · 3 mins read Java

1. Intro

자바에서 사용되는 JVM(Java Virtual Machine)의 역할에 대해서 살펴보고 왜 필요한 것인지 알아보려고 한다.

2. JVM(Java Virtual Machine)

Java

JVM은 운영체제(OS)와 JAVA 언어간의 중개자 역할을 하면서 어떤 운영체제를 사용하더라도 같은 JAVA 코드를 이용해서 실행 할 수 있도록 도와준다. 또한 가장 중요한 메모리 관리를 담당하므로써 개발자가 일일히 객체의 할당된 메모리를 해제하지 않아도 Garbage Collector가 Garbage Collection을 수행한다.

가상 머신의 종류에는 스택 기반 가상머신과 레지스터 기반 가상머신이 존재하는데, X86 및 ARM 아키텍처에서 사용되는 레지스터 기반 가상머신과 달리 JVM은 스택 기반 가상머신에 속한다. 이에 대한 내용은 차후에 설명하도록 하겠다.

3. JAVA 프로그램의 실행 과정

Java JVM

앞서 말한 JVM의 실행 과정이다. 이제 JVM 위에서 자바 프로그램이 어떻게 수행이 되는지 알아보자.

4. JVM의 구조

4.1 Java Compiler

JAVA compiler는 우리가 만든 .java파일을 컴파일해 바이트코드로 만들고 이를 .class파일에 저장하는 역할을 한다.

4.2 Class Loader

Class Loader는 저장된 .class파일들을 읽어와 운영체제로부터 할당받는 메모리 공간인 Runtime Data Areas에 적재하는 역할을 한다.

이러한 역할은 자바 어플리케이션이 실행 될 때만 수행된다.

4.3 Execution Engine

Execution Engine(실행 엔진)Class Loader에 의해 Runtime Data Areas에 적재된 바이트 코드화 된 클래스들을 기계어로 변경해 명령어 단위로 실행하는 역할을 한다.

바이트 코드는 기계가 바로 수행하기 보다는 비교적 사람이 보기 쉬운 형태의 고급언어에 가깝기 때문에 JVM 내부에서 기계가 쉽게 일을 수행할 수 있도록 2가지 방법을 이용하여 바이트 코드를 변경한다.

4.3.1 Interpreter

Execution Engine(실행 엔진)은 바이트코드를 명령어 단위 별로 읽어와서 실행한다. 하지만 인터프리터의 단점을 그대로 가지고 있기 때문에 한 줄 씩 수행하고, 그 때문에 속도가 느리다는 단점을 가지고 있다.

4.3.2 JIT Compiler

JIT compiler는 이러한 인터프리터의 단점을 고치기 위해서 도입된 컴파일러이다. 적절한 시간에 전체 바이트 코드를 네이티브 코드로 변경해서 Execution Engine이 네이티브로 컴파일된 코드를 실행하는 방식으로 되어 성능을 높일 수 있다.

4.4 Runtime Data Area

Java Runtime Data Area

Runtime Data Area는 JVM에서 메모리에 존재하는 영역으로 자바 어플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.

이 영역은 크게 Method Area, Heap Area, Stack Area, PC Register, Native Method Stack으로 나눌 수 있다.

4.4.1 Method Area

클래스와 인터페이스에 존재한 상수 풀 및 멤버 변수, 클래스 변수(Static 변수), 생성자 및 메소드를 저장하는 공간이다.

4.4.2 Heap Area

Java heap

Heap영역은 JVM에서 런타임시 동적으로 할당하여 사용하는 영역으로서 New 연산자로 생성된 객체 또는 객체와 배열을 저장한다. 또한 참조하는 변수, 필드가 없다면 제거 대상이 되는 객체로 GC의 대상이 된다.

여기서 Young GenerationOld Generation 영역은 자바 어플리케이션 단에서 사용하는 부분이다.

기존에는 Permanent 영역이 존재하였지만 JAVA8 이후로는 이 부분이 사라지고 Native 영역에 Metaspace 영역이 생겼다.

4.4.3 Stack Area

쓰레드 마다 스택이 하나 씩 존재하며, 스레드가 시작 될 때 할당된다. 선입 후출(LIFO) 구조로 push, pop 기능을 사용한다. 원시타입(Primitive type) 변수는 스택 영역에 직접적인 값을 가진다.

4.4.4 PC Register

현재 수행 중인 JVM의 명령 주소를 갖는 부분으로 메모리에 데이터 전달 전에 저장 한다.

4.4.5 Native Method Stack

Java가 아닌 언어로 작성된 네이티브 코드들을 저장하기 위한 Stack이다. JNI, JNA 모두 이 부분을 이용하여 C/C++ 코드를 수행하기 위해 필요하다. 또한 네이티브 메소드의 매개변수, 지역변수 등을 바이트 코드로 저장한다.