JVM(자바가상머신) 이란?
JVM은 자바 언어를 공부하는데 처음이자 끝이라고 생각이 듭니다.
Java 언어로 작성된 소스코드는 컴파일러를 통해 컴파일되어 바이트코드로 변환되는데 이를 해석하고 실행하는 것이 JVM이라고 할 수 있습니다. 쉽게 보면 Java 위에 JVM이 위를 살짝 덮어 어떠한 운영체제 상에서도 실행 될수 있게 하는 중개자라고 아시면 되겠습니다.
JVM의 구조를 살펴보겠습니다.

추가적으로 바이트 코드는 기계어가 아니기 때문에 OS(운영체제)에서 실행이 불가 합니다.
기계가 읽을 수 있게 대신 해석해준다는 것은 Java의 큰 장점이겠죠? 또한 어떠한 OS에도 영향을 받지 않기때문에 의존성을 줄여 독립적이라는 특성도 가지고 있습니다.
그러면 JVM의 구성요소는 어떻게 될까요?

Class Loader(클래스 로더)
JVM내로 클래스(.class파일)를 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈입니다. Runtime 시에 동적으로 클래스를 로드하여 바이트 코드를 읽고 메모리에 저장합니다. 또한 jar파일 내 저장된 클래스들을 JVM위에 탑재하고 사용하지 않는 클래스들은 메모리에서 삭제하게 됩니다. 즉, 클래스를 처음으로 참조할 때, 해당 클래스를 로드하고 링크한다는 것이고 그 역할을 클래스 로더가 수행한다고 보시면 됩니다.
Execution Engine(실행 엔진)
클래스를 실행시키게 되면 클래스 로더가 JVM내의 런타임 데이터 영역에 바이트 코드를 배치시키고, 이것은 실행엔진에 의해 실행됩니다. 바이트코드는 기계가 알지 못하기 때문에 실행 엔진은 이와 같은 바이트코드를 실제로 JVM내부에서 기계가 실행할 수 있는 형태로 변경하는 역할을 합니다. 이 때 두 가지 방식을 사용하게 됩니다. 이와 같은 단점을 보완하기 위해 JIT 컴파일러가 만들어졌습니다. 실행엔진은 인터프리터 방식으로 실행되다가 적절한 시점에서 바이트 코드를 컴파일하고 이를 캐시에 보관하여 한번 컴파일된 코드는 그대로 불러와 빠르게 사용하는 방식입니다.
- 인터프리터
실행엔진은 바이트 코드를 명령어 단위로 한줄씩 순차적으로 실행합니다. 이는 C언어 같은 네이티브 언어에 비해 속도가 느린 단점이 있습니다.
- JIT (Just In Time)
이와같은 단점을 보완하기 위해 JIT 컴파일러가 만들어졌습니다. 실행엔진은 인터프리터 방식으로 실행하다가 적절한 시점에 바이트코드를 컴파일하고 이를 캐시에 보관하여 한번 컴파일된 코드는 그대로 불러와 빠르게 사용하는 방식입니다.
결국, 자바는 인터프리터와 컴파일을 둘다 사용함으로 느린 속도를 보완해주게 되는겁니다.
Garbage collector
Garbage Collector(GC)는 이후에 자세하게 다룰 예정인데 간단히 설명하자면 Heap 메모리 영역에 생성된 객체들 중에 참조되지 않은 객체들을 제거하는 역할을 합니다. GC의 동작시간은 일정하게 정해져 있지 않기 때문에 언제 객체를 정리할지는 알 수 없습니다. 바로 참조가 없어지자마자 작동하는 것이 아니라 Heap 영역에서 저장되어있다가 필요없게 된 메모리 영역(어떠한 변수도 가리키지 않게 된 영역)을 탐지하여 삭제합니다. 또한 GC가 수행되는 동안 GC를 수행하는 쓰레드가 아닌 다른 모든 쓰레드가 일시정지가 되는 특징이 있습니다.
Runtime Data Area
JVM의 메모리 영역으로 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역입니다.
- Method area (메소드 영역)
클래스 멤버 변수의 이름, 데이터 타입, 접근 제어자 정보같은 필드 정보와 메소드의 이름, 리턴 타입, 파라미터, 접근 제어자 정보같은 메소드 정보, Type정보(Interface인지 class인지), Constant Pool(상수 풀 : 문자 상수, 타입, 필드, 객체 참조가 저장됨), static 변수, final class 변수등이 생성되는 영역입니다.
- Heap area (힙 영역)
new 키워드로 생성된 객체와 배열이 생성되는 영역입니다. 또한 메소드 영역에 로드된 클래스만 생성이 가능하고 Garbage Collector가 메모리를 관리할때 사용하는 영역이기도 합니다.
- Stack area (스택 영역)
지역 변수, 파라미터, 리턴 값, 연산에 사용되는 임시 값등이 생성되는 영역입니다. int a = 10; 이라는 소스를 작성했다면 정수값이 할당될 수 있는 메모리공간을 a라고 잡아두고 그 메모리 영역에 값이 10이 들어갑니다. 즉, 스택에 메모리에 이름이 a라고 붙여주고 값이 10인 메모리 공간을 만든다고 이해 하시면 될것 같습니다. 또한 메소드를 호출할 때마다 개별적으로 스택영역이 생성됩니다.
- PC Register (PC 레지스터)
Thread(쓰레드)가 생성될 때마다 생성되는 영역으로 Program Counter 즉, 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장하고 있는 영역입니다. (*CPU의 레지스터와 다름) 이것을 이용해서 쓰레드를 돌아가면서 수행할 수 있게 합니다.
- Native method stack
네이티브 메서드(C, C++ 등 자바 이외의 언어로 작성 된 코드)가 저장되는 메모리 공간 입니다.
그래서 결국 JVM이 무엇이냐? 한문장으로 정리하자면 JVM의 내부 동작을 통해 컴파일된 Java 소스코드를 어떠한 운영체제에서든 읽을 수 있게 기계어로 해석해주고 Garbage Collector(GC)를 통해 자동으로 메모리관리 까지 해주는 역할을 하는 가상머신이다.!! 라고 정리할 수 있겟습니다.
사실 자바에 있어 아주 중요한 역할을 하지만 프로그래밍을 하다보면 자동으로 해주기때문에
사소하게 넘어갈 수 있는 부분인것 같습니다.
그러나 사소하지만 핵심적인 JVM이 무엇인지 알고 넘어가면 좋을 것 같습니다.
부족한 글 읽어 주셔서 감사합니다. 잘못된 내용 있으면 지적해주시면 감사하겠습니다.
하얀종이개발자
'Java' 카테고리의 다른 글
자바의 애노테이션은 어떻게 사용하는 걸까? @interface의 진짜 의미와 활용법 (0) | 2024.03.11 |
---|