JVM 메모리의 이해
JVM기반 어플리케이션을 서비스 할 때는 규모가 작을 경우는 잘모르고 지나가도 운좋게 아무 문제 없이 지나갈 수 있지만, 규모가 조금이라도 큰 경우 잘못된 JVM 메모리 설정에 의해 엄청난 문제를 초래할 수 있다. 그래서 JVM 메모리 구조와 각 요소 별 역할에 대해서 기록 한다.
Runtime Data Area
JVM 메모리라고 하면 Runtime Data Area를 말하는 것인데, 해당 영역은 아래와 같이 Method Area, Heap Area, Stack Area, PC 레지스터, Native Method Stack 이 5가지 세부 영역을 가진다.
- Method Area
클래스 파일을 읽어 분석한 뒤 클래스의 인스턴스 변수, 메소드 코드, 클래스 변수 등을 저장하는 메모리 영역.
저장되는 내역- Type Information
- Runtime Contant Pool
- Field Information
- Method Information
- Class Variable
- 외 몇가지..
- Heap Area
JVM이 인스턴스를 생성하면 할당되는 메모리 영역.
우리가 흔히 아는 Garbage Collection(이하: GC)가 동작하는 대상이 되는 영역. - Stack Area
스레드를 제어하기 위해 사용되는 메모리 영역.
실행되는 Method가 순서대로 쌓이게 된다.
Method가 실행되면 Stack에서 나오고, 종료되면 메모리 상에서 제거 된다.
스레드 별로 생성된다. - PC 레지스터
Stack Area와 마찬가지로 스레드 별로 생성.
JVM 명령 주소가 저장. - Native Stack Area
자바 이외의 언어로 작성된 코드가 할당되는 메모리 영역.
Heap Area
JVM 메모리를 조정 및 관리 하기 위해서는 Heap Area 영역이 어떻게 구성되고 동작하는지 알아야 한다. 위 그림을 보면 알 수 있듯이 Heap 영역은 Youn Generation, Old Genration, Permanent Generation 이렇게 크게 3가지 영역으로 나뉜다. 차례 대로 하나씩 알아 보자.
- Young Genration - (Eden, Survivor0, Survivor1)
새롭게 생성된 인스턴스가 할당되는 영역.
Eden 영역의 메모리가 가득찬 상태에서 또 인스턴스를 생성하면 Eden을 대상으로 Minor GC가 동작하게 되고, 생존자 객체가 하나의 생존자 공간으로 이동하게 된다.
여기서 중요한 점은 2개의 생존자 공간 중 하나는 항상 비어 있다는 것이다. (여기서 중요하다고 한 이유는… 이거 몰라서 첨에는 왜 쓸데 없이 자꾸 하나는 0의 값을 가지냐고 의문을 품음..)
Young Genration의 목적은 새로운 인스턴스를 빠르게 할당하고 지속적으로 사용되는 인스턴스를 Old Genration으로 이동시키는 것이다. - Old Genration
지속적으로 사용되고, Minor GC에 의해 제거되지 않은 인스턴스가 저장되는 메모리 영역이다. 흔히 우리가 아는 GC가 동작하는 대상이다. - Permanent Genration
해당 Genration은 Java8 버전이 되면서 사라 졌지만 8이하 버전을 사용하는 경우도 많으므로 알고 가야 할거 같아서 찾아서 정리해본다. Permanent Genration에는 아래와 같은 내용들이 저장된다.- Class의 Meta 정보
- Method의 Meta 정보
- Static Object
- 상수화된 String Object
- Class와 관련된 배열 객체 Meta 정보
- JVM 내부적인 객체들과 최적화 컴파일러(JIT)의 최적화 정보
- Metaspace
Java8이 되면서 기존의 Permanent Genration은 없어지고 Metaspace라는 영역이 생겼다. 이전의 있던 Permanent Generation을 왜 없앴는지 생각해보자. 위 그림에서 보면 알 수 있듯이 Permanent Genration은 GC의 대상이 아니다. 그런데 Permanent Genration에 저장되는 항목들 중에 GC의 대상이 되어야 할 몇가지 항목이 보인다. Static Object와 상수화된 String Object이다. 프로그램이 커지고 저 두개의 사용 빈도가 커지게 되면 JVM은 계속 해서 java.lang.OutOfMemoryError: PermGen space 오류를 나타 내게 될 것이다. 그래서 Java8에서는 이러한 문제를 개선하기 위해 기존의 Permanent Genration을 없애버리고 Metaspace를 사용하게 된 것이다.
Metaspace에서 Static Object와 상수화된 String Object를 제외하고는 기존의 Permanent Generation 항목들은 그대로 저장한다.
해당 영역의 설정은 -XX:MetaspaceSize, –XX:MaxMetaspaceSize 로 설정한다.
Heap Memory 설정
- -xms
JVM이 시작 할 때 설정될 초기 Heap Size - -xmx
최대 Heap Size - -xmn
Young Generation Size - -XX:PermGen
초기 Permanent Generation Memoery Size - -XX:MaxPermGen
최대 크기 Permanent Generation Memoery Size - -XX:MetaspaceSize
초기 MetaspaceSize - -XX:MaxMetaspaceSize
최대 MetaspaceSize
정리
JVM 메모리 구조에 대해서 정리를 했다. 다음 정리에는 GC가 어떻게 동작하는지에 대해서 정리를 해보자.
참고 자료
https://limkydev.tistory.com/51
https://hongsii.github.io/2018/12/20/jvm-memory-structure/
https://www.holaxprogramming.com/2013/07/16/java-jvm-runtime-data-area/
https://betsol.com/java-memory-management-for-java-virtual-machine-jvm/
https://www.journaldev.com/2856/java-jvm-memory-model-memory-management-in-java
Comments