1. JVM 메모리 구조

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

런타임 데이터 영역은 JVM의 메모리 영역으로 자바 어플리케이션이 실행할 때 사용되는 데이터를 적재하는 영역이다.

크게 5가지로 나눌 수 있다. Method Area, Heap, Stack, PC Register, Native Method Stacks
각 영역의 용도와 공유 범위를 구분하면 아래 사진과 같다.

img.png

즉, Method Area, Heap Area는 모든 스레드가 공유하는 영역이며, 나머지 Stack Area, PC Register, Native Method Stack는 각 스레드마다 개별 생성되는 영역이다. 각 영역에 대한 상세히 살펴보자.

1. 메서드 영역 (Method Area)

같은 표현: Class Area, Static Area

JVM이 시작될 때 생성되는 공간으로 바이트 코드(.class)를 처음 메모리 공간에 올릴 때 초기화되는 대상을 저장하기 위한 공간이다. 즉, JVM이 동작하고 클래스는 로드될 때 적재되서 프로그램이 종료될 때까지 저장된다.

모든 스레드가 공유하는 영역이기 때문에 아래와 같이 초기화 코드 정보들이 저장되게 된다.

메서드 영역은 쉽게 말해 정적 필드와 클래스 구조만 갖고 있다고 이해하면 된다.

1.1 사용 기간 및 스레드 간 공유 범위

메소드 영역과 런타임 상수 풀은 JVM 시작 후 클래스 로딩 과정에서 생성되며, JVM 종료 시 해제된다. 단, 클래스 언로딩이 발생하면 해당 클래스의 메타데이터와 런타임 상수 풀도 해제될 수 있다. 일반 객체 참조를 null로 만드는 것은 힙 객체를 GC 대상으로 만들 수는 있지만, 메소드 영역 자체를 직접 해제하는 행위는 아니다.

1.2 런타임 상수 풀(Runtime Constant Pool)

한 줄 정리: 런타임 상수 풀은 클래스 실행 중 필요한 상수 값과 클래스, 필드, 메서드 참조 정보를 저장하고, JVM이 바이트코드를 실행하면서 필요한 대상을 찾아 연결할 수 있게 돕는 메소드 영역의 자료구조다.

런타임 상수 풀은 메서드 영역에 존재하는 별도의 관리 영역으로, 클래스 생성과 실행에 필요한 상수와 참조 정보를 JVM이 런타임에 찾아 쓰기 좋게 보관하는 영역이다. 각 클래스와 인터페이스 마다 별도의 Constant Pool 테이블이 존재한다.

런타임 상수 풀은 Class 혹은 interface가 생성될 때 함께 생성된다. 구체적으로, 바이트코드(.class) 내부에 constant_pool이라는 테이블이 존재하는데, JVM이 해당 클래스를 로딩하면 이 constant_pool를 바탕으로 런타임 상수 풀을 메서드 영역에 생성한다.

저장되는 정보는 대표적으로 클래스 이름 정보, 필드 참조 정보, 메서드 참조 정보, 등이 들어가게 되는데 어떤 클래스의 어떤 필드, 메서드를 가리키는지에 대한 참조 정보도 저장된다.

System.out.println("hi");

예를 들어, 해당 코드를 실행시키려면, JVM은 System 클래스가 어디에 있는지, out 필드는 무엇인지 println 메서드는 어떤 메서드인지, "hi" 문자열 리터럴은 무엇인지에 대한 정보를 런타임 상수 풀에서 찾고, 필요하면 실제 메모리 주소나 메서드 정보로 연결해야 한다. 이 과정을 동적 링크라고 한다.

여기서 런타임 상수 풀에 저장되는 참조 정보로, 실제 메모리 주소가 저장되는 것은 아니다. 메모리 주소는 프로그램 실행시 JVM이 클래스를 어디에 올릴지에 따라 달라지기 때문에, 바이트코드(.class)에 있는 constant_pool에 작성된 심볼릭 레퍼런스가 런타임 상수 풀에 올라오며, 이를 기반으로 JVM이 실행 과정에서 동적 링크를 진행한다.

2. 힙 영역 (Heap Area)

JVM이 관리하는 프로그램 상에서(어플리케이션) 데이터를 저장하기 위해 런타임시 동적으로 할당하여 사용하는 영역이다. 메서드 영역과 마찬가지로 모든 스레드가 공유한다.

즉, 컴파일 시점이 아닌 런타임 시점에 new 연산자로 생성되는 인스턴스 변수나 배열 타입 등 Reference Type이 저장되는 곳이다.

Method 영역에서 저장된 클래스만이 실제 생성되어 힙 영역에 저장된다.

즉, 클래스 로더가 .class 파일을 로드하면 클래스 이름, 부모 클래스, 메서드, 필드, 런타임 상수 풀 등의 클래스 메타데이터가 Method 영역에 저장된다. 이후 new 연산 등으로 객체가 생성될 때, 이 클래스 정보를 기반으로 인스턴스가 생성되어 Heap 영역에 저장되는 것이다.

2.1 사용 기간 및 스레드 간 공유 범위

객체가 더 이상 사용되지 않거나, 명시적으로 객체 값에 null 선언시(즉, 메모리 주소를 해제) 해제된다. 힙 메모리에 있는 객체는 GC 대상이다.

2.2 힙 영역 참조 위치

힙 메모리에 생성된 객체와 배열은 Reference Type이기 때문에, JVM의 스택 영역의 변수나 다른 객체의 필드에서 해당 힙 메모리 주소를 참조하고 있다. 따라서, 힙 메모리 참조 주소는 스택이 갖고 있고, 해당 객체를 통해서만 인스턴스를 사용할 수 있다.