본문 바로가기

CS

JVM 메모리 구조

JVM이란?

Java Virtual Machine의 약자로 자바 가상 머신이다. Java는 OS에 종속적이지 않다는 특징을 가지고 있다. OS에 종속 받지 않고 실행되기 위해 JVM이 자바와 OS 사이에서 중계자 역할을 수행한다.

위의 흐름은 자바 프로그램이 실행되는 과정을 보여준다. 개발자가 작성한 .java 소스 코드는 javac 컴파일러를 통해 .class 확장자의 바이트코드 파일로 변환된다. 이렇게 생성된 바이트코드는 JVM이 읽어 들여 ClassLoader를 통해 메모리에 로딩한 뒤 Execution Engine에서 해석하거나 JIT(Just-In-Time) 컴파일러를 이용해 기계어로 변환한다. 최종적으로 변환된 기계어는 CPU에 의해 실행되어 자바 프로그램이 동작하게 된다.

JVM 내부 구조

1. Class Loader

JVM 내로 클래스 파일을 로드하고, 링크를 통해 배치하는 작업을 수행하는 모듈이다.

즉, 로드된 바이트 코드(.class)들을 엮어서 JVM의 메모리 영역인 Runtime Data Areas에 배치한다. 클래스를 메모리에 올리는 로딩 기능은 한번에 메모리에 올리지 않고, 어플리케이션에서 필요한 경우 동적으로 메모리에 적재하게 된다.

2. Execution Engine

Execution Engine은 JVM 메모리에 로딩된 바이트코드를 실제로 해석하고 실행하는 역할을 한다. 대표적으로 두 가지 방식이 있다.

  • 인터프리터: 바이트코드를 한 줄씩 해석하면서 실행한다. 기본적으로 이 방식으로 동작하지만 같은 메소드가 여러번 호출된다면 매번 해석하고 수행해야 되기 때문에 전체적인 속도가 느리다.
  • JIT(Just-In-Time) 컴파일러: 자주 실행되는 코드를 Native Code로 변경하고, 이후에는 해당 메서드를 더 이상 인터프리팅 하지 않고 캐싱해 두었다가 네이티브 코드로 직접 실행하는 방식이다.

이러한 방식으로 바이트코드는 CPU가 이해할 수 있는 수준으로 해석되며, 실제 실행이 이루어진다.

3. Garbage Collector

Garbage Collector(GC)는 Heap 메모리 영역에서 더는 사용하지 않는 메모리를 자동으로 회수한다. 일반적으로 자동으로 실행되고, GC가 실행되는 시간은 정해져 있지 않다.

4. Runtime Data Area (JVM 메모리 영역)

Runtime Data Area는 자바 애플리케이션을 실행할 때 사용되는 데이터들을 적재하는 영역이다.

  • Method Area
    • 클래스 정보(클래스 이름, 부모 클래스 이름, 메소드와 변수 정보 등)가 저장되는 영역이다. 전역 변수와 static 변수를 저장하며, Method 영역은 프로그램의 시작부터 종료까지 메모리에 남아있다. 모든 쓰레드가 공유하는 영역이다.
      • Field Info : 멤버 변수의 이름, 데이터 타입, 접근 제어자의 정보
      • Method Info : 메소드 이름, return 타입, 함수 매개변수, 접근 제어자의 정보
      • Type Info : Class 인지 Interface 인지 여부 저장, Type의 속성, 이름 Super Class의 이름
    • JVM이 동작해서 클래스가 로딩될 때 생성된다.
    • 스태틱 메소드가 스태틱 변수만 참조할 수 있는 이유
    • 스태틱 메소드와 변수는 메소드 영역에 저장되어 동일한 메모리를 공유한다. 또한, 메소드 영역에 저장된 데이터만 접근할 수 있기 때문에 스태틱 메소드는 인스턴스 변수에 접근할 수 없다.
  • Stack
    • 지역 변수와 매개 변수 데이터 값이 저장되는 공간이다.
    • 메서드 호출 시마다 각각의 스택 프레임(그 메서드만을 위한 공간)이 생성되고 메서드 안에서 사용되는 값들을 저장하고, 호출된 메서드의 매개변수, 지역변수, 리턴 값 및 연산 시 일어나는 값들을 임시로 저장한다.
    • LIFO 구조를 갖고 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다.
    • 스택 영역은 각 스레드마다 하나씩 존재하며, 스레드가 시작될 때 할당된다.
  • Heap
    • new 연산자로 생성되는 클래스와 인스턴스 변수, 배열 타입 등 Reference Type이 저장되는 곳이다.
    • 모든 쓰레드가 공유하는 영역이다.
    • 런타임시 동적으로 할당하여 사용하는 영역이다.
    • 데이터 타입에 따라 스택과 힙에 저장되는 방식이 다르다.
      • 기본(원시)타입 변수는 스택 영역에 직접 값을 가진다.
      • 참조타입 변수는 힙 영역이나 메소드 영역의 객체 주소를 가진다.

  • 예를 들어 Person p = new Person(); 와 같이 클래스를 생성할 경우 new 에 의해 생성된 클래스는 Heap Area 에 저장되고, Stack Area 에는 생성된 클래스의 참조인 p 만 저장된다.
String s = new String("hello");
  • s는 스택 영역에 있다. (참조 변수)
  • "hello"라는 실제 문자열 객체는 힙 영역에 있다.
  • s는 힙에 있는 "hello"의 주소(참조값)를 가지고 있다.

즉, 힙의 참조 주소는 "스택"이 갖고 있고 해당 객체를 통해서만 힙 영역에 있는 인스턴스를 핸들링할 수 있는 것이다.

  • 가비지 컬렉션에 의해 메모리가 관리되어 진다.

힙의 객체는 스택의 참조 타입 변수와 연결되어 있다. 만일 참조하는 변수나 필드가 없다면 의미 없는 객체가 되기 때문에 이것을 쓰레기로 취급하고, JVM은 Garbage Collector를 실행시켜 쓰레기 객체를 힙 영역에서 자동으로 제거한다.

  • PC Register
    • PC 레지스터는 쓰레드가 시작될 때 생성되며, 현재 수행중인 JVM 명령어 주소를 저장하는 공간이다.
    • 만약에 스레드가 자바 메소드를 수행하고 있으면 JVM 명령(Instruction)의 주소를 PC Register에 저장한다. 그러다 만약 자바가 아닌 다른 언어(C언어, 어셈블리)의 메소드를 수행하고 있다면, undefined 상태가 된다. 왜냐하면 자바에서는 이 두 경우를 따로 처리하기 때문이다. 이 부분이 바로 뒤에 언급하게 될 Native Method Stack 공간이다.
  • Native Method Stack
    • 네이티브 메서드 스택은 자바 코드가 컴파일되어 생성되는 바이트 코드가 아닌 실제 실행할 수 있는 기계어로 작성된 프로그램을 실행시키는 영역이다. 앞서 JIT 컴파일러에 의해 변환된 Native Code가 여기서 실행 된다.
    • 또한, 자바 이외의 언어(C, C++, 어셈블리 등)로 작성된 네이티브 코드를 실행하기 위한 공간이기도 하다.
    • 네이티브 메소드 스택은 JNI와 연결되어 있다. JNI가 사용되면 네이티브 메서드 스택에 바이트 코드로 전환되어 저장되게 된다.

5. JNI (Java Native Interface)

  • JNI는 자바가 C, C++ 등의 네이티브 언어로 작성된 코드와 상호 작용할 수 있도록 해주는 인터페이스이다.
  • 자바에서 native로 선언된 메서드는 JVM이 실행 시 Native Method Stack에 적재되며,
  • 이때 JNI를 통해 네이티브 라이브러리(C/C++)의 함수와 연결되어 실행된다.

6. Native Method Library

  • C, C++ 등으로 작성된 네이티브 코드가 컴파일된 라이브러리를 의미한다.
  • 자바에서 native 메서드가 호출될 때 JVM은 이 네이티브 라이브러리를 메모리에 로딩하고, JNI를 통해 해당 메서드를 연결하여 실행한다.

참고

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

https://asfirstalways.tistory.com/158

https://dev-coco.tistory.com/153

'CS' 카테고리의 다른 글

컴파일과 빌드 차이  (0) 2025.07.04
CPU, 주기억장치(RAM), 보조기억장치  (0) 2025.07.04