서론
Spring Batch Job 실행 중 다음과 같은 에러가 발생했다
2024-09-10T05:35:03.820Z ERROR 1 --- [gazapos_db][ AsyncThread-19] o.s.batch.core.step.AbstractStep : Encountered an error executing step backupStep in job backupJob
java.lang.OutOfMemoryError: Java heap space
이 에러로 인해 DB 읽기를 제외한 create, update, delete 등의 트랜잭션 처리가 불가능한 상황이 되었다. 이를 해결하기 위해 JVM의 Heap Memory 영역에 대해 알아보고, JVM 메모리 구조를 이해해 보고자 한다.
JVM (Java Virtual Machine)
JVM은 자바 프로그램의 실행 환경을 제공하는 가상 머신으로, 자바의 플랫폼 독립성을 보장한다.

JVM 작동 과정

- 자바 컴파일러가 .java 파일을 .class 바이트 코드로 컴파일한다.
- JVM이 바이트 코드를 해당 OS에 맞는 바이너리 코드로 변환한다.
- 변환된 코드를 컴퓨터(CPU)가 실행한다.
JVM 실행 단계
- main 메서드를 포함한 클래스를 실행한다.
- 컴파일러가 소스를 바이트 코드로 컴파일한다.
- 컴파일된 코드가 JVM의 클래스 로더로 전달된다.
- 클래스 로더가 JVM 메모리 영역에 클래스 파일을 할당한다.
- 실행 엔진이 바이트 코드를 바이너리 코드로 해석하여 실행한다.
Runtime Data Area (JVM 메모리 영역)
JVM 메모리 영역은 자바 애플리케이션 실행 시 사용되는 데이터를 저장하는 영역이다.

메모리 영역 구성
| 영역 | 설명 |
|---|
| Method Area | - 클래스 구조, 메서드, 필드, static 변수 등 저장 - 모든 스레드가 공유 |
| Heap Area | - 동적으로 생성된 객체와 배열 저장 - 가비지 컬렉터의 관리 대상 |
| Stack Area | - 메서드 실행 관련 정보 저장 - 메서드 매개변수, 지역변수, 임시 데이터 |
| PC Register | - 현재 실행 중인 JVM 명령의 주소 저장 |
| Native Method Stack | - 네이티브 코드 실행을 위한 스택 영역 |
스레드 공유 여부

- 스레드 별 생성: Stack Area, PC Register
- 모든 스레드 공유: Heap Area, Method Area
Heap Area 상세 구조

Young Generation
- Eden: 새로 생성된 객체 저장
- Survivor 0/1: GC 후 살아남은 객체 이동
Old Generation
- Young Generation에서 오래 살아남은 객체 저장
- 메이저 가비지 컬렉션 대상
Stack vs Heap
- 저장 데이터: Stack은 기본 타입, Heap은 참조 타입 객체
- 크기 결정: Stack은 컴파일 타임, Heap은 런타임에 결정
- 메모리 관리: Stack은 자동 해제, Heap은 GC가 관리
- 데이터 구조: Stack은 연속적, Heap은 임의의 위치에 할당
PC Register의 역할
- JVM의 PC Register: 다음 실행할 바이트코드 주소 저장
- CPU의 PC Register와의 차이: 자바는 바이트코드를 사용하므로 별도의 PC Register 필요
네이티브 메서드 스택
- 자바 외 언어로 작성된 네이티브 코드를 위한 스택 영역
- JNI(Java Native Interface)를 통해 실행되는 코드를 위한 별도의 스택
참고 및 이미지 출처: https://developer111.tistory.com/33