JVM의 구성요소 중, 데이터 영역에 대한 설명으로 아래의 내용들에 대해서 다루어 보도록 하겠다
Runtime Data Areas란
Runtime Data Areas의 구성 요소
스레드 별로 존재
PC Register
JVM Stack
Native Method Stack
스레드 공유
Runtime Data Areas란
출처:(https://m.blog.naver.com/writer0713/221137837754)
JVM은 Java 컴파일러 가 컴파일한 ByteCode를 ClassLoader 를 이용해 메모리(RuntimeDataArea )에
실행 가능한 상태로 적재한다.
RuntimeDataArea는 JVM이 프로그램을 수행하기 위해 OS로부터 별도로 할당받은 메모리 영역이다.
Runtime Data Areas의 구성 요소
출처 : (https://hongsii.github.io/2018/12/20/jvm-memory-structure/)
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의 대상이다.
출처:(https://www.slideserve.com/kinsey/memory-management-case-study-jvm-clr)
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구조를 살펴보도록 하겠다
출처:(https://mirinae312.github.io/develop/2018/06/04/jvm_memory.html)
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 )
permGen OOM
위와 같은 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
출처:(http://karunsubramanian.com/websphere/one-important-change-in-memory-management-in-java-8/)
포스팅을 위해 구글링을 하는 동안 헷갈렸던 부분을 다시 집으면
Method Area와 Permanent Generation의 차이가 뭐냐 (설명으로는 비슷해 보이는데)
PermGen에 Method Area가 포함되어있다
Heap의 구성요소를 찾아보면 young, old, perm이 나오는데 Permanent Generation은 Heap의 구성요소가 맞냐
내가 이해한 그림
참고 내역 :)