Java

[JVM 밑바닥까지 파헤치기] 2. 자바 메모리 영역과 메모리 오버플로

noahkim_ 2024. 12. 19. 17:21

저우즈밍 님의 "JVM 밑바닥까지 파헤치기" 책을 정리한 포스팅 입니다

 

1. 런타임 데이터 영역

 

  • JVM이 프로그램을 실행하는 동안 데이터를 저장하고 관리하기 위해 사용하는 메모리 구조

 

영역

영역 이름 설명
주요 특징 및 구성 요소
메서드 영역 클래스 메타데이터 영역  
힙 영역 객체 인스턴스가 저장되는 영역 - GC 관리 대상
JVM 스택 메서드 호출 시마다 생성되는 스레드 기반 스택 - 스택 프레임 단위 구성
프로그램 카운터 (PC) 현재 스레드가 실행 중인 바이트코드의 줄 번호를 저장
- 스레드마다 별도 존재
- 네이티브 메서드 실행 시 비어 있음
네이티브 메서드 스택 C 등의 네이티브 메서드 실행용 스택
- JNI 등 호출 시 사용

 

표) 메서드 영역

더보기
구분 저장 내용 설명
클래스 메타데이터 클래스 이름 클래스의 식별 정보
  부모 클래스 정보 상속 구조 정보
  접근 제어 정보 public, private 등
  구현 인터페이스 implements 정보
필드 및 메서드 정보 필드 이름 및 타입 멤버 변수 구조 정보
  메서드 이름 및 시그니처 메서드 정의 정보
  메서드 바이트코드 실행할 명령어 코드
정적 변수 (static) 클래스 변수 클래스 단위 공유 변수
런타임 상수 풀 리터럴 상수 숫자, 문자열 등
  심볼 참조 클래스/필드/메서드 이름 정보

 

표) 힙 영역

더보기
영역 이름 설명
주요 특징 및 구성 요소
Young Generation 새로운 객체가 생성되는 영역
- Eden, Survivor 구역
Old Generation 장기 생존 객체 저장
- Full GC 대상
TLAB 각 스레드 전용의 객체 할당 공간
- 동시 할당 충돌 방지, 성능 향상 목적

 

표) JVM 스택 영역

더보기
영역 이름 설명
주요 특징 및 구성 요소
지역 변수 테이블 메서드 내 지역 변수 저장
- 32bit 슬롯 단위 (32bit, 64bit)
- 기본 타입, 참조, 반환 주소 등 저장
피연산자 스택 계산에 필요한 값 임시 저장
- 연산 명령어 실행 시 사용됨
동적 링크 및 반환 주소 메서드 호출/복귀 정보 유지
- 호출자와 피호출자 간 연결 정보

 

2. 핫스팟 가상 머신에서의 객체 들여다보기

객체 메모리 레이아웃

  • 객체가 힙에 생성될 때, 크게 3부분으로 메모리 레이아웃이 구성됨
구성 요소 설명
주요 내용 및 목적
객체 헤더 JVM이 객체를 관리하기 위해 추가하는 메타데이터 블록
마크 워드, 클래스 워드, (배열의 경우 배열 길이 포함)
인스턴스 데이터 실제 필드값이 저장되는 영역
- 부모 → 자식 클래스 순서
- 타입 크기 순 정렬 ➡️ 메모리 효율 최적화
정렬 패딩 8바이트 정수배로 맞추기 위해 존재  

 

표) 객체 헤더

더보기
구성 요소 설명
주요 내용
Mark word 객체의 런타임 정보
해시코드, GC 나이, 락 상태, 타임스탬프 등
Klass Pointer 클래스 메타데이터 주소
해당 객체가 어떤 클래스의 인스턴스인지 알려줌
배열 길이 배열인 경우만 존재
배열의 요소 개수 저장

 

객체 접근 방식

항목 다이렉트 포인터 방식 핸들 방식
구조 객체 참조가 힙의 객체 주소를 직접 가리킴 객체 참조가 핸들 테이블의 엔트리를 가리킴
접근 속도 빠름 (중간 참조 없음)
느림 (간접 참조 필요)
GC 시 객체 이동 모든 참조를 업데이트 해야 함
핸들만 수정하면 됨
참조 안정성 낮음 (객체 이동 시 참조 오류 가능)
높음 (핸들이 추상화 계층으로 보호함)

 

객체 생성 과정

  1. 심볼 참조 확인: new 명령어의 대상이 상수 풀에 존재하는 클래스 심볼인지 확인
  2. 클래스 로딩 여부 확인: 해당 클래스가 이미 로딩되어 있는지 검사
  3. (클래스 로딩)
  4. 메모리 할당
  5. 필드값 설정 (zero-initialization)
  6. 객체 헤더 설정: 생성된 객체에 필수 메타정보 설정 (클래스 포인터, 해시코드, GC 나이 등)
  7. 생성자 호출

 

과정) new 명령어

더보기
  1. 상수풀에서 클래스의 심볼 참조를 확인 (CONSTANT_Class → "com/example/User")
  2. 심볼 참조를 실제 참조로 변환함 (Klass*)
  3. 힙에 메모리를 할당하고 객체를 생성함

✅ 심볼 참조: 클래스의 이름 정보. 실행 시점에 실제 객체 생성을 위한 메타데이터의 포인터로 변환됨

 

3. OutOfMemoryError

  • JVM이 새로운 객체나 메모리를 할당하려 했으나, 사용할 수 있는 메모리가 부족할 때 발생하는 에러
오버플로 종류 발생 조건/설명 예외 클래스
Heap OOM 힙에 객체를 더이상 할당이 불가함 OutOfMemoryError
Metaspace OOM 메타스페이스 초과 OutOfMemoryError
Native Memory OOM ByteBuffer.allocateDirect() 사용 시 설정된 한도 초과 OutOfMemoryError
스택 오버플로 재귀로 스택 프레임 과다 StackOverflowError

 

옵션) Heap OOM

더보기
  • -Xms: 최소 힙 크기 지정
  • -Xmx: 최대 힙 크기 지정
  • -XX:+HeapDumpOnOutOfMemoryError: OOM 발생 시 힙 덤프 생성

 

옵션) 스택 오버플로

더보기
  • -Xss: 스레드당 스택 크기 설정

 

옵션) Metaspace OOM

더보기
  • -XX:MetaspaceSize: 초기 메타스페이스 크기
  • -XX:MaxMetaspaceSize: 최대 메타스페이스 크기
  • -XX:MinMetaspaceFreeRatio: 최소 여유 공간 비율 설정

 

옵션) Native Memory OOM

더보기
  • -XX:MaxDirectMemorySize: 다이렉트 메모리 최대 사용량 제한

 

 

출처