JVM 공부하기

JVM

JVM이란, Java Virtual Machine의 약자로서, 직역하면 자바를 실행하는 머신입니다.

JVM을 사용하면 자바 프로그램을 모든 플랫폼에서 제약 없이 동작할 수 있습니다.

JVM을 이해하기 위해서 어떻게 자바 코드가 실행되는지 먼저 알아보겠습니다.


자바는 C언어와 함께 대표적인 컴파일 언어입니다.

여기서 말하는 컴파일(Compile)이란, 우리가 작성한 코드를 컴퓨터가 이해할 수 있는 과정으로

바꾸는 일종의 번역 과정입니다.

우리가 동작시키는 자바 프로그램들은 모두 다음과 같은 과정을 거칩니다.

  1. Java 소스 파일(.java)을 작성합니다.
  2. javac 명령어로 소스 파일을 컴파일하여 바이트 코드(.class)를 생성합니다.
    • 바이트 코드는 운영 체제에 무관하게 동일합니다.
  3. JVM은 java 명령어를 사용해 바이트 코드를 기계어로 변환하며 실행합니다.

JDK 🆚 JRE

자바를 사용하기 위해서 설치하는 도구는 JDK와 JRE 두 가지로 나뉩니다.

  • JDK(Java Developement Kit)
    • 자바를 사용하기 위한 모든 기능을 갖춘 도구 상자(JRE를 포함)
    • 대표적인 도구는 컴파일러, javadoc 등이 있다.
  • JRE (Java Runtime Environment)
    • JVM과 자바 프로그램을 실행(동작)시킬 때 필요한 라이브러리 API를 함께 묶어서 배포되는 패키지
    • 자바 가상 머신과 자바 표준 라이브러리(ex. java.lang)를 가지고 있다.

바이트 코드

JVM이 읽을 수 있는 사용자 언어(자바)와 기계어 중간 수준의 언어입니다.

컴파일의 결과물로 .class 확장자를 가집니다.

변환된 코드의 명령어 크기가 1 byte라서 바이트 코드 라고도 불립니다.


JVM의 구조

바이트 코드를 JVM에 넘겨주면 클래스 로더가 런타임 데이터 영역에 로드하고,

실행엔진(Execution Engine)이 바이트 코드를 실행 시켜 주면서 자바 프로그램이 동작합니다.


클래스 로더

클래스 로더는 JVM 내에서 클래스를 로딩하고, 다른 클래스와의 관계를 설정하며, 초기화를 수행하는 중요한 구성 요소입니다.

클래스 로더에는 부트스트랩 클래스 로더, 확장 클래스 로더, 애플리케이션 클래스 로더 등 여러 종류가 있으며, 각각 로드하는 클래스의 범위와 역할이 다릅니다.

부트스트랩 클래스 로더

  • 모든 클래스 로더의 부모가 되는 클래스 로더입니다.
  • rt.jar 를 JVM에 로드합니다.
  • 다른 클래스 로더와 다르게 운영체제(OS)에 맞는 네이티브 코드로 작성되어 있습니다.
  • rt.jar : 자바 표준 라이브러리 클래스를 포함하는 jar 파일 (ex. java.lang 등)

확장 클래스 로더

  • 특정 경로(jre/lib/ext)에 위치한 클래스들을 JVM에 로드합니다.
  • 다양한 보안 확장 기능 등을 로드합니다.

애플리케이션 클래스 로더

  • 다른 로더가 JVM의 구성을 로드했다면, 이 로더는 작성한 클래스($CLASSPATH 내의 클래스)를 JVM에 로드합니다.

클래스 로더가 위임 방식을 사용하는 이유는 로드 요청이 먼저 상위 클래스 로더로 전달되어, 해당 클래스가 이미 로드되어 있는지 확인하기 위해서입니다.

이 과정에서 상위 클래스 로더는 하위 클래스 로더의 네임스페이스에 접근할 수 없으며, 이러한 특성을 가시성(Visibility) 제한이라고 합니다.

JVM에서 클래스 로딩과 초기화 과정은 다음과 같은 단계로 이루어집니다

  1. 로딩 (Loading)
    • 클래스 또는 리소스를 JVM 메모리에 올리는 과정입니다.
  2. 링킹 (Linking)
    • 검증 (Verification)
      • TCK(Technology Compatibility Kit)를 통해 클래스 파일의 유효성을 검사합니다.
      • 이 과정에서 클래스 파일 포맷, 메모리 오버플로우 등을 확인하며, 실패 시 VerifyError를 던집니다.
    • 준비 (Preparation)
      • 클래스 변수에 메모리를 할당하고, 기본값으로 초기화합니다.
      • 이 메모리는 메서드 영역(Method area)에 존재하며, static 블록이 있는 경우 이를 실행합니다.
    • 해석 (Resolution)
      • 클래스나 인터페이스의 이름으로 실제 클래스 파일을 찾아, 참조 값을 주입합니다.
      • 이는 ClassPath에서 실제 클래스 파일을 찾고, 클래스 파일 내 모든 심볼릭 레퍼런스를 다이렉트 레퍼런스로 변경하는 작업입니다.
  3. 초기화 (Initializing)
    • 준비 단계에서 기본값으로 초기화된 클래스 변수들을 작성자가 정의한 값으로 초기화하는 과정입니다.

실행 엔진 (Execution Engine)

모든 과정을 거쳐 메모리에 로드된 바이트 코드는 실행 엔진에 의해 기계어로 변환되어 실행됩니다. 이 과정에서 “OpCode”라는 명령어가 사용되며, “바이트 코드”라는 이름도 여기서 유래합니다.

바이트 코드를 기계어로 변환하는 과정은 컴파일과 유사하게 번역이 필요한데, 실행 엔진은 이를 위해 두 가지 방법을 사용합니다

  • 인터프리터 (Interpreter)
    • 바이트 코드 명령어를 하나씩 읽어서 즉시 해석하여 실행합니다.
    • 해석 속도는 빠르지만, 실행 속도는 상대적으로 느립니다.
  • JIT 컴파일러 (Just-In-Time Compiler)
    • 인터프리터의 느린 실행 속도를 보완하기 위해 도입된 방식입니다.
    • IR(Intermediate Representation)이라는 중간 언어를 사용하여 바이트 코드를 번역합니다.
    • 해석 속도는 다소 느리지만, 번역된 코드를 실행할 때는 매우 빠르게 동작합니다.

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

JVM이라는 프로그램이 메인 OS로부터 받은 메모리 공간을 의미합니다.
Method,Heap,Stack,PC Register,Native Method Stack 이라는 5개의 영역으로 구분되어 있습니다.

이때 Method와 Heap 영역은 모든 스레드가 공유합니다.
반면에, Stack, PC Register, Native Method 세 영역은 스레드마다 하나씩 생성됩니다.

  • PC 레지스터 (Program Counter Register)
    • 현재 실행 중인 JVM 명령어의 주소를 저장합니다.
  • 스택 영역 (Stack Area)
    • 스택 프레임(Stack Frame)을 저장하는 영역으로, 각 스레드의 작업 목록을 관리합니다.
    • 각 스택 프레임은 지역 변수 배열, 피연산자 스택, 그리고 해당 클래스의 상수 풀(Constant Pool)에 대한 참조를 포함합니다.
    • 피연산자 스택은 연산을 수행하기 위한 임시 저장 공간이며, 상수 풀 참조는 클래스의 필드를 불러오기 위한 링크입니다.
    • printStackTrace() 메서드에서 보여지는 각 라인은 하나의 스택 프레임을 나타냅니다.
  • 네이티브 메서드 스택 (Native Method Stack)
    • 자바 외의 언어로 작성된 네이티브 코드를 실행하기 위한 스택입니다.
    • 시스템 라이브러리와의 호환성을 유지하기 위해 존재합니다.
  • 메서드 영역 (Method Area, Class Area, Static Area)
    • JVM이 시작될 때 생성되며, 모든 스레드가 공유하는 공간입니다.
    • 종료될 때까지 유지되며, 인스턴스 생성에 필요한 정보를 포함합니다.(객체 구조, 생성자, 필드 등)
    • 또한, 이 영역에는 런타임 상수 풀(Runtime Constant Pool), static 변수, 메서드의 바이트 코드 등이 저장됩니다.
    • 런타임 상수 풀은 각 클래스의 상수와 메서드, 필드에 대한 참조를 저장하는 테이블입니다.
  • 힙 영역 (Heap Area)
    • 인스턴스를 저장하는 공간으로, JVM이 시작될 때 생성되어 종료될 때까지 유지됩니다.
    • 이 영역에 저장된 모든 인스턴스는 Reference Type이며, JVM 스택 등에서 참조됩니다.
    • 힙 영역은 가비지 컬렉션(GC)에 의해 관리되며, 메모리가 부족하면 OutOfMemoryError가 발생할 수 있습니다.

참고자료

https://tecoble.techcourse.co.kr/post/2021-07-12-jvm-jre-jdk

https://inpa.tistory.com/entry/JAVA-☕-JVM-내부-구조-메모리-영역-심화편


답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다

Captcha loading…