[JAVA] JVM과 자바 코드의 동작

kindof

·

2021. 6. 17. 16:22

1. JVM이란 무엇인가?

JVM(JAVA Virtual Machine)은자바 애플리케이션을 클래스 로더를 통해 읽어 들여 자바 API와 함께 실행해주도록 하는 가상 머신입니다.

 

JVM은 JAVA와 OS 사이에서 중개자 역할을 하는데, 덕분에 JAVA가 OS에 구애받지 않고 재사용을 가능하게 해줍니다. 가상 머신 도입의 가장 근본적인 이유이기도 하죠.

 

한편, 또 하나의 JVM의 중요한 역할 중 하나는 Garbage Collection(GC)을 통한 메모리 관리인데요. GC(Garbage collection)에 대해서는 아래 포스팅에서 자세히 정리했습니다.

 

 

[JAVA] 가비지 컬렉션(Garbage Collection, GC)에 대한 이해

0. 들어가기 전에 자바 가비지 컬렉터(GC)에 대해 설명하기 전에 스택과 힙 영역에 대해 잠깐 짚고 넘어가려고 하는데요. 이 부분을 모른 채로 GC를 이해하는 것이 좀 어려울 것 같다고 생각합니다

studyandwrite.tistory.com

 

자, 그러면 이제 JVM에 대해 본격적으로 알아보겠습니다.

 

JVM은 스택 기반의 가상머신입니다. 스택 기반의 가상 머신이란 무엇일까요?

스택 기반 가상 머신

 

스택 기반 가상 머신은 피연산자와 연산 후 결과를 스택에 저장합니다.

 

예를 들어 위와 같이 덧셈 연산을 진행할 경우, 스택 구조이기 때문에 두 개의 피연산자를 POP하고 ADD 연산을 한 뒤 PUSH를 하는 4단계의 명령이 필요하죠.

 

이 때, JVM은 다음 피연산자의 메모리 위치를 기억할 필요가 없습니다. 스택에서 POP 연산을 진행하게 되면 그 자체가 바로 다음 피연산자가 되기 때문이죠.

 

따라서, JVM이 스택 기반 가상머신이라는 사실은 한정된 메모리를 효율적으로 사용하기 유리하다는 것을 의미합니다.

 

동일한 기능의 프로그램이더라도 메모리 관리에 따라 성능이 좌우되기 때문에 메모리 관리가 되지 않는 경우 속도저하 현상이나 튕김 현상 등이 일어날 수 있겠죠. 

 

 

2. JVM은 어떻게 Java 코드를 컴파일하고 실행하는가?

Compile(컴파일)이란 개발자가 작성한 소스코드를 바이너리 코드로 변환하는 과정을 말합니다. 즉, 컴퓨터가 이해할 수 있는 기계어로 변환하는 작업이죠.

 

자바의 경우, JVM에서 실행가능한 바이트코드 형태의 클래스파일이 생성됩니다. 그 과정을 살펴보겠습니다.

 

* 잠깐, 자바 바이트 코드란?

  • 자바 바이트코드란 JVM이 이해할 수 있는 언어로 변환된 자바 소스 코드를 의미합니다. 자바 컴파일러에 의해 변환되는 코드의 명령어 크기가 1바이트라서 자바 바이트코드라고 불립니다.
  • 자바 바이트코드의 확장자는 .class입니다.

 

JVM을 통해 코드가 실행되는 과정

1. 프로그램이 실행되면 JVM은 OS로부터 이 프로그램이 필요로 하는 메모리를 할당받습니다. JVM은 이 메모리를 용도에 따라 여러 영역으로 나누어 관리하죠.


2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킵니다. 위 그림 왼쪽 상단의 회색 부분을 보시면 됩니다.


3. 클래스 로더(Class Loader)는 .class파일들을 읽고 바이트 코드를 메서드 영역(Method Area)에 저장합니다. 각 .class 파일은 JVM에 의해 메서드 영역에 다음의 정보들을 저장합니다.

  • 로드된 클래스를 비롯한 그의 부모 클래스 정보
  • class 파일이 Class, Interface, Enum과 관련이 있는지 여부
  • 변수나 메서드의 정보 등

4. .class파일이 로딩(Loading)된 후, JVM은 힙 메모리 영역에 이 파일이 나타내는 클래스 유형의 객체를 생성합니다.

 

5. 이 후 클래스 로더는 Linking을 통해 여러개로 분리된 소스파일들을 컴파일한 결과물들 중에서 최종 실행 가능한 파일을 만들기 위해 필요한 부분을 찾아서 연결해줍니다.

 

6. static으로 선언된 변수와 메서드에 메모리를 할당하고 초기값을 Initialize합니다.


7. .class 파일들은 Execution engine을 통해 해석됩니다.


8. 해석된 바이트코드는 Runtime Data Area에 배치되어 실질적인 수행이 이루어지게 됩니다.


9. 이러한 실행과정 속에서 JVM은 필요에 따라 Thread Synchronization과 GC같은 관리 작업을 수행합니다.

 

 

3. JVM 구성 요소

위에서 JVM이 자바 파일을 컴파일하고 실행하는 과정을 살펴봤습니다.

 

이 과정에서 클래스 로더를 통해 Loading, Linking, Initialization을 했고, 실행 엔진을 통해 .class파일을 해석하여 Runtime에 실질적인 수행이 이루어지게 됐죠.

 

이러한 JVM의 구성요소에 대해 한 번 다시 정리해봅시다.

 

Class Loader(클래스 로더)

JVM 내로 클래스(.class)를 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈입니다.

 

Runtime 시에 동적으로 클래스를 로드하죠. jar 파일 내 저장된 클래스들을 JVM위에 탑재하고, 사용하지 않는 클래스들은 메모리에서 삭제합니다.

 

자바는 컴파일 타임이 아니라 런타임에 클래스를 참조합니다. 즉, 클래스를 처음으로 참조할 때 해당 클래스를 로드하고 링크하는 것이고 이 역할을 클래스 로더가 수행하는 것입니다.

 

Execution Engine(실행 엔진)

클래스를 실행시키는 역할을 합니다.

 

클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행엔진에 의해 실행됩니다.

 

자바 바이트코드는 기계가 바로 수행할 수 있는 언어보다는 비교적 인간이 보기 편한 형태로 기술된 것이죠.

 

그래서 실행 엔진은 이와 같은 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경하는데, 이 때 클래스 파일을 실행시키는 방법에 따라 크게 두 가지 방식을 사용하게 됩니다.

 

Interpreter(인터프리터)

  • 실행 엔진은 자바 바이트 코드를 명령어 단위로 읽어서 실행합니다. 하지만 이 방식은 인터프리터 언어의 단점을 그대로 갖고 있습니다. 한 줄씩 수행하기 때문에 느리다는 것이죠.

 

JIT(Just-In-Time)

  • 인터프리터 방식의 단점을 보완하기 위해 도입된 것이 JIT 컴파일러입니다. 인터프리터 방식으로 실행하다가 적절한 시점에 바이트코드 전체를 컴파일하여 Native Code(네이티브 코드)로 변경하고, 이후에는 더 이상 인터프리팅 하지 않고 네이티브 코드로 직접 실행하는 방식입니다. 네이티브 코드는 캐시에 보관하기 때문에 한 번 컴파일된 코드는 빠르게 수행하게 되죠.
  • 물론 JIT컴파일러가 컴파일하는 과정은 바이트코드를 인터프리팅하는 것보다 훨씬 오래 걸리기 때문에 한 번만 실행되는 코드라면 컴파일하지 않고 인터프리팅 하는 것이 유리할 수 있습니다. 따라서 JIT 컴파일러를 사용하는 JVM들은 내부적으로 해당 메서드가 얼마나 자주 수행되는지 체크하고, 일정 정도를 넘을 때에만 컴파일을 수행합니다.

 

4. JDK와 JRE의 차이?

처음에 자바를 설치하면 jre, jdk 등을 설치하고 환경변수를 설정하고..일단 이유는 모르고 그냥 시키는대로 하는 경우가 많습니다. 두 녀석의 차이점에 대해 살펴봅시다.

JDK와 JRE

  • JRE
    • JRE는 Java Runtime Environment의 약자로 자바 프로그램을 실행시켜주는 환경을 구성해주는 도구입니다. 즉 JAVA를 개발할 필요는 없지만, 실행은 시켜줘야 하는 경우에는 꼭 JRE가 있어야합니다. 반면 JAVA를 개발하려면 JDK가 필요하죠.
  • JDK
    • JDK는 Java Development Kit의 약자로 말그대로 자바 개발 시 필요한 툴킷을 제공하는 도구모음입니다. 개발하려면 당연히 실행도 시켜야하므로 JDK 안에 JRE가 포함되어 있습니다.

 

 

5. 나가면서

이번 포스팅에서는 자바 어플리케이션의 컴파일 과정과 JVM이 어떤 역할을 하고 어떤 구성으로 되어 있는지에 대해 살펴보았는데요.

 

이 내용들은 자바 어플리케이션이 실행되고 동작하는 기본적인 메커니즘이니, 한 번쯤 머리에 새겨보면 좋겠습니다.

 

감사합니다.