[JAVA] JVM 메모리 구조, 데이터 영역 ( Runtime Data Areas)
- -
JVM의 구성요소 중, 데이터 영역에 대한 설명으로 아래의 내용들에 대해서 다루어 보도록 하겠다
- Runtime Data Areas란
- Runtime Data Areas의 구성 요소
- 스레드 별로 존재
- PC Register
- JVM Stack
- Native Method Stack
- 스레드 공유
- Method Area
- 상세 구조
- Heap
- 상세 구조
- Java8부터 달라진 점
- Method Area
- 스레드 별로 존재
Runtime Data Areas란
JVM은 Java 컴파일러가 컴파일한 ByteCode를 ClassLoader를 이용해 메모리(RuntimeDataArea)에
실행 가능한 상태로 적재한다.
RuntimeDataArea는 JVM이 프로그램을 수행하기 위해 OS로부터 별도로 할당받은 메모리 영역이다.
Runtime Data Areas의 구성 요소
Runtime Data Area는
PC Registers, JVM Stacks, Method Area, Heap, Native Method Stacks으로 구성된다.
이 중 PC Register, JVM Stack, Native Method Stack은 각 스레드 별로 존재한다.
각 쓰레드마다 서로 다른 메모리가 할당된다.
PC Register
- 현재 수행 중인 JVM 명령의 주소
- Thread가 생성될 때마다 생기는 공간으로 Thread가 어떠한 명령을 실행하게 될지에 대한 부분을 기록
- JVM은 Stacks-Base 방식으로 작동하는데, JVM은 CPU에 직접 Instruction을 수행하지 않고, Stack에서 Operand를 뽑아내 이를 PC Register에 저장
JVM Stack
- 각각 스레드가 시작될 때 생성
- Stack Frame을 저장하는 스택
- 메서드가 수행될 때마다 하나의 스택 프레임이 생성되어 해당 스레드의 JVM stack에 추가되고
메서드가 종료되면 스택 프레임이 제거- Stack Frame은 Local Variable Array, Operand Stack, Constant Pool의 레퍼런스를 갖는다.
Native Method Stack
- 자바 외의 언어로 작성된 네이티브 코드를 위한 스택
- Java Native Interface를 통해 호출하는 C/C++ 코드를 수행하기 위한 스택
Heap과 Method Area는 각각의 스레드가 메모리를 공유한다.
Method Area는 클래스 데이터를 위한 공간이라면 Heap 영역이 객체를 위한 공간
Method Area는 변하지 않는 Constant 값들이 존재하기 때문에 각 스레드들이 메모리를 공유하더라도 문제가 없다.
Heap은 Garbage Collection의 대상이다.
Method Area
모든 Thread들이 공유하는 메모리 영역
프로그램 실행 중 클래스가 사용되면 JVM은 해당 클래스 파일을 읽어서 분석하여 클래스의 인스턴스 변수, 메서드 코드 등을 Method Area에 저장한다
Java 8 이전에는 Method Area를 PermGen(Permanat Generation Space)에 할당했다.
Java 8 이후에는 PermGen이 완전히 제거되어 Method Area는 Native Heap에 할당된다.
- Type information
- Type은 클래스와 인터페이스를 통칭하는 것으로 이해하면 된다
- 클래스와 관련한 모든 정보
- Constant Pool
- 문자열 상수와 같은 리터럴 상수
- 메서드와 필드에 대한 모든 Reference를 담고 있음 (Symbolic Reference)
즉, 어떤 메서드나 필드를 참조할 때, JVM은 런타임 상수 풀을 통해 메서드나 필드의 실제 메모리 상 주소를 참조하여 중복을 막는 역할
- Field Information
- Class 멤버 변수의 이름 및 데이터 타입, 접근 제어자에 대한 정보를 저장
- Method Information
- Class 멤버 메서드의 이름, 리턴 타입, 매개변수, 접근제어자에 대한 정보
- Class Variable
- static으로 선언되는 모든 클래스 변수
- 이 변수는 모든 Instance에서 접근 가능하기 때문에 동기화 이슈가 발생할 수 있음
Class Variable을 final로 선언할 경우에는 Constant Pool에 저장
- Reference to ClassLoader & class Class
- 특정 클래스를 로드한 클래스로더의 정보를 관리
- Class object와 서로 양방향 접근을 하기 대문에 Class Object에 대한 참조 주소 값을 가진다
- Method Table
- Class의 Method에 대한 Direct Reference를 가진다고 보면 된다
- Method Table을 이용해 Super Class에서 상속된 Method의 Reference까지 확인이 가능
Heap
- JVM이 관리하는 프로그램 상에서 데이터를 저장하기 위해 런타임 시 동적으로 할당하여 사용하는 영역
- new 연산자로 생성된 객체 또는 인스턴스와 배열을 저장
- 힙 영역에서 생성된 객체와 배열은 스택 영역의 변수나 다른 객체의 필드에서 참조
- 참조하는 변수나 필드가 없다면 의미 없는 객체가 되어 GC의 대상이 된다
Heap의 구조는 JVM을 구현한 vender마다 다르다.
대표적으로 Oracle의 Hotspot JVM Heap구조를 살펴보도록 하겠다
GC가 발생하는 영역이며, 참조(레퍼런스)가 없는 객체들은 GC과정을 통해 메모리에서 제거된다.
Heap 영역 또한 내부적으로 여러 영역으로 나뉘어 있으며, 이는 객체의 lifecycle 및 GC와 연관되어 있다.
GC(Garbage Collection)와 관련된 내용은 다른 포스팅을 통해서 자세히 소개하도록 하겠다.
Young Generation : Eden 영역과 Survivor영역으로 구성
- Eden 영역
- Object(객체)가 최초로 Heap에 할당되는 장소
- 만일 Eden 영역이 가득 찼다면, Object의 참조 여부를 파악하고 LiveObject는 Suvrvior 영역으로 넘긴다
- 모든 LiveObject가 Survivor영역으로 넘어간다면 Eden영역을 청소 (참조가 사라진 GarbageObject)
- Survivor 영역
- Survivor0과 Survivor1로 구성
- Eden영역에 살아남은 Object들이 잠시 머무르는 곳이며 LiveObject들은 하나의 Survivor 영역만 사용
- 이러한 전반적인 과정을 Minor GC
Old Generation
- Survivor1 또는 Survivor2 영역을 왔다 갔다 하는 과정에서 끝까지 살아남은 객체만이 Old 영역으로 이동
- 보통 Old 영역은 Young 영역보다 크게 할당하며, 이러한 이유로 Old 영역의 GC는 Young 영역보다 적게 발생
- Old Generation의 메모리가 충분하지 않으면 해당 영역에서 GC가 발생하는데 이를 Major GC
Permanent Generation
- Class의 Meta정보나 Method의 Meta정보, Static변수와 상수 정보들이 저장되는 공간, 흔히 메타데이터 저장 영역
- 객체의 생명 주가기 길다고 판단되는 객체들을 이 영역에 할당하여 GC대상에서 제외를 하기 위해서 만들어진 영역
- 주로 자바의 Class 객체들이나 문자열에 속한 String 객체들이 위치
대략적인 설명만으로는 위에서 설명한 Method Area와 겹친다는 생각이 든다
그래서 해당 내역을 찾아본 결과, Permanent Generation은 Method Area를 포함하고 있다
(stackoverflow.com/a/60066513/9923340)
위와 같은 Exception은 Heap의 구성 중, Permanent Generation의 memory가 부족한 현상이다
이러한 현상이 일어나는 요인으로는 아래의 것들이 있을 수 있다
- static Object의 잘못된 사용
- Class, Method Meta data의 증가
이러한 문제를 해결(?) 하기 위해서 Java8 버전에서부터는 Permanent Generation이 존재하지 않는다
해당 영역을 MetaSpace로 대체하였다
- Static Object 및 상수화된 String Object를 heap 영역으로 옮김으로써, 최대한 GC가 될 수 있도록 수정
(interned Strings and class static variables will be moved from the permanent generation to either the Java heap or native memory)
java heap 또는 native memory라는 표현 - Metaspace 영역은 Heap이 아닌 Native 메모리 영역으로 취급
(Heap 영역은 JVM에 의해 관리된 영역이며, Native 메모리는 OS 레벨에서 관리하는 영역으로 구분) - Perm 영역 메모리 크기 옵션 -XX:PermSize / -XX:PermMaxSize,
Metaspace 영역 메모리 크기 옵션 -XX:Metaspace / -XX:MaxMetaspaceSize
포스팅을 위해 구글링을 하는 동안 헷갈렸던 부분을 다시 집으면
- Method Area와 Permanent Generation의 차이가 뭐냐 (설명으로는 비슷해 보이는데)
- PermGen에 Method Area가 포함되어있다
- Heap의 구성요소를 찾아보면 young, old, perm이 나오는데 Permanent Generation은 Heap의 구성요소가 맞냐
- 아니라고 한다 - stackoverflow.com/questions/41358895/permgen-is-part-of-heap-or-not
- 그렇다면, 위에서 설명한 Heap의 구성요소에 속하는 PermGen 설명은 틀린 것..
내가 이해한 그림
참고 내역 :)
'Java' 카테고리의 다른 글
[Java] java.security.egd option (0) | 2023.06.28 |
---|---|
[Java] ThreadLocal이란 (0) | 2022.11.24 |
[JAVA] 로드타임, 런타임 동적로딩 (Load-Time, Run-Time Dynamic Loading) (0) | 2022.08.10 |
[JAVA] 정적, 동적 바인딩 (Static, Dynamic Binding) (2) | 2022.08.06 |
[JAVA] ClassLoader란, 원칙, 계층구조, 로딩단계 (0) | 2022.08.02 |
소중한 공감 감사합니다