////
Search

1. JVM 메모리 구조

Created
2022/09/04 10:56
Tags
JVM

1. JVM이란?

JVM - Java Virtual Machine
Virtual의 의미
JVM은 물리적인 형태가 아닌 소프트웨어로서 하나의 개념으로 존재한다.
Machine의 의미
JVM은 독자적으로 작동할 수 있는 메커니즘과 구조를 가지고 있다.
하나의 v축약된 컴퓨터와 같은 의미다.
JVM이 구체적으로 무엇이냐는 질문에 정확한 정의를 내린다기 보다는 하나의 개념, 스펙에 지나지 않는다.
어느 누구도 정확하고 자세한 설계도를 제공하지 않는다.
표준화된 정의만이 존재할 뿐이다.
각 JVM 벤더들은 표준에 맞도록 자신의 JVM을 별도로 구현한다.
즉 JVM은 정의된 스펙을 구현한 하나의 독자적인 프로세스 형태로 구동되는 Runtime Instance라고 할 수 있다.
그림1
Class Loader
JVM 내로 class파일들을 Load 하여 Loading된 클래스들을 Runtime Data Area에 배치
Execution Engine
Loading된 클래스의 Bytecode를 해석
Runtime Data Areas
JVM이라는 프로세스가 프로그램을 수행하기 위해 OS에서 할당받은 메모리 공간

JVM 아키텍처

Method Area
클래스, 변수, 메소드, static 변수, 상수 정보 등이 저장되는 영역
Heap Area
new 명령어로 생성된 인스턴스와 객체가 저장되는 구역
Stack Area
Method 내에서 사용되는 값들(매개변수, 지역변수, 리턴값 등)이 저장되는 구역
메소드 호출시마다 메모리에 LIFO로 생성/삭제된다.
PC Register
PC 레지스터와 역할이 비슷하고, JVM 명령의 주소값이 저장된다.
Native Method Stack
다른 언어(C/C++ 등)의 메소드 호출을 위해 할당되는 구역으로 얼어에 맞게 Stack이 형성되는 구조

1.2 Java Heap

Java의 Heap영역은 메모리 자동해제, 즉 GC(Garbege Collection)과 연관이 깊다.
사람들이 자바의 메모리 구조는 곧 Heap이라 오해하지만, 여러 다른 메모리 영역도 존재한다.
Heap은 Instance와 Array객체 두 가지 종류만 저장되는 공간일 뿐이다.
Heap은 데이터가 공유되어 동기화 문제 이슈가 발생할 수 있다.
JVM은 Heap에 Memory를 할당하는 Instruction만 존재하고 메모리 해제를 위한 어던 Java Code나 Bytecode도 존재하지 않는다.
메모리 해제는 오직 GC를 통해서만 수행된다.
이 또한 정해진 부분 없이 벤더마다 다를 수 있다.

1.2.1 Hotspot JVM의 Heap 구조

Young Generation은 Eden과 Survivor영역으로 구성된다.
이 영역에서 일어나는 GC를 Minor GC라 말한다.
Eden은 최초로 메모리에 할당되는 장소이며 꽉 차게 되면 참조 여부를 체크해 Live Object라면 Survivor영역으로 넘어가고 아니라면 GC에 의해 메모리에서 해제된다.
Survivor영역은 말 그대로 살아남은 Object들이 잠시 머무르는 장소로 2개의 영역이 있지만 하나의 영역만을 사용한다.
Young Generation에서 오래 살아남은 객체는 Old Generation으로 이동된다.
이 영역에서 일어나는 GC를 Full GC라고 한다.
특정 회수 이상 참조되어 Age를 초과한 Object를 의미한다.
Perm 영역은 보통 Class의 Meta 정보나 Method의 Meta 정보, Static 변수와 상수 정보 등이 저장되는 공간으로 흔히 메타데이터 저장 영역이라고도 한다.
자바 8에서 JVM 메모리 구조적 개선사항으로 Perm 영역이 Metaspace영역으로 전환되어 Perm 영역은 사라지게 되었다.
해당 Metaspace 영역은 Native 메모리에서 관리된다.

1.2.2 Java 8의 Metaspace 초기치와 최대치 확인

./java -XX:+PrintFlagsFinal -version -server | grep MetaspaceSize
Shell
복사
위 명령어를 실행하면 7버전의 경우 82MB, 8버전의 경우 16Exabyte라는 매우 큰 수치를 볼 수 있다.
16ExaByte는 64Bit 프로세서가 취급할 수 있는 메모리 상한치다.
Metaspace 영역은 Native 메모리로 다루기 때문에 프로세스가 이용할 수 있는 메모리 자원을 최대한 활용할 수 잇다고 본다.
그러나 이 메모리 크기도 별도의 옵션(MaxMetaspaceSize)을 통해 제한이 가능한다.
Classloader에 메모리 누수가 의심될 경우 -XX:MaxMetaspaceSize를 지정할 필요가 있다고 본다.
Metaspace는 만능의 영역이 아니기 때문에 기존 발생한 메모리 누수가 완벽하게 해소되지는 않는 것으로 보인다.
기존엔 메모리 누수가 의심되는 환경에서 Perm 영역의 상한값이 모종의 제한 역할을 했다.
Metaspace 영역에서는 기본적으로 이 제한의 역할이 존재하지 않기 대문에 무한하게 메모리 영역이 확대될 수 있다.
Metaspace는 필요에 따라 자동적으로 메모리 상한치가 증가하기 때문에 일반적으로 크게 주의를 가지고 설정할 필요가 없다.

1.2.3 IBM JVM의 Heap 구조

IBM JVM의 Heap은 Java 1.4.X 이전과 Java 5 이후를 기준으로 달라진 부분이 있다.
1.4.2 까지는 System Heap과 Heap으로 구분되었으나 5부터는 이러한 구분이 사라졌다.
5부터는 GC의 설정에 따라 Generational Heap 구성이 가능해졌다.
5에 와서 IBM JVM의 Heap에서는 두 가지의 큰 변화가 있었다.
System Heap을 더 이상 포함하지 않게 된 것
Hotspot JVM과 같이 Generational Heap을 사용할 수 있게 된 것
GC옵션 중 Genetation Concurrent 옵션인 `-Xgcpolicy:gencon을 추가하고 JVM을 시작하면 아래 그림과 같은 형태의 Heap이 구성된다.
Hotspot JVM의 Young Generation역할을 하는게 Nursery Genetation이다.
Object가 생성된지 얼마 되지 않아 Garbege가 되어 사라지는 것을 흔히 유아 사망률(Infant Mortality)이라 한다.
이에 착안해 탁아소라는 명칭을 사용한듯 하다.
Nursery도 Allocate와 Survior 영역으로 나뉘게 된다.
Allocate는 Object가 최초로 할당되는 곳이다.
Survior은 Allocate 영역이 꽉 차거나 다른 이유로 인해 Allocate Failure이 발생하게 되면 Allocate영역의 Live Object를 대피시키는 곳이다.
이 또한 GC의 과정이다.
Tenured 영역은 Nursery영역의 성숙한 Object들을 Promotion하는 곳이다.