JVM의 역할
- 컴파일된 자바클래스파일(자바바이트코드)를 읽어 운영체제에 맞게 프로그램으로 실행시키는 가상머신이다. 자바코드를 컴파일하면 기계어가 아닌 바이트코드로 변환되는데 이때 운영체제에서 바이트코드를 읽을수 있도록 해석해주는 역할이다.
- 가비지컬렉터를 이용해서 메모리 관리도 담당한다. Java7부터는 G1GC가 나와서 힙영역의 객체들을 관리하는 역할도 담당한다.
- OS에 종속적이다. 윈도우의 JVM과 리눅스의 JVM은 다르다
JVM의 구성요소
- ClassLoader / ExecutionEngine / Memory(Runtime Data Area) / Native 크게 네가지로 나눠볼 수 있다.
- .class파일(바이트코드)를 불러와서 JVM메모리에 로드한다. 로딩된 클래스는 runtime data area에 배치된다.
- 클래스에 있는 static값을 초기화한다
- ClassLoader : 자바 바이트코드를 실제 메모리에 올리는 역할을한다. 로딩된 클래스는 runtime data area에 배치된다.WAS마다 방식이 조금씩 다르다고 한다.
- ExecutionEngine : 바이트코드를 읽고 CPU가 해석가능한 기게어로 번역하여 실행하는 역할을 한다. Interpreter방식과 JIT방식을 동시에 사용한다.
- Memory : Method Area / Heap Area / Stack Area / PC registers / Native Method stack으로 나눠볼 수 있다.
- Native : 자바에서 C, C++, Assembly로 작성된 API를 사용할 수 있도록 해주는 역할을 한다.
JVM의 Generation메모리구조
- 가비지 컬렉션이 수행될때 모든 객체가 가비지인지 검사하는 방식은 어플리케이션의 규모가 커지면 커질수록 문제가 생길 수 있음에 따라서 가비지 컬렉팅을 수행할때마다 모든 객체를 검사하는게 아니라 일부만 검사할 수 있도록 Generation 구조라는것을 사용한다.
- young generation : 객체가 생성될 때 이곳으로 가고, 영제네레이션이 가득차면 minor gc가 발생한다. minor gc가 발생하면 살아있는 객체들만 체크하고 나머지는 다 없애버린다. 살아남은 객체들 중 더 오래쓸것 같은 것들은 tenured generation으로 옮긴다.
- tenured generation : major gc가 이루어지는 곳이다.
JVM의 메모리구조(Run-Time Data Areas) - Java SE8기준
- 데이터 영역중 일부는 JVM실행부터 종료시까지 항상 존재하고, 다른 데이터영역은 스레드의 생명주기와 같이 생성되고 소멸된다.
Heap Area
- 모든 JVM쓰레드 사이에 공유되는 영역이다. 모든 클래스의 인스턴스객체와 배열이 여기에 저장된다.
- JVM이 시작할때 생성되고 Heap영역에 할당된 데이터는 GC의 대상이다. 각 객체를 지정하여 메모리 할당을 해제하는것이 불가능하지만 GC를 튜닝하는것은 가능하다.
- 동적으로 할당되는 데이터가 저장되는 영역이다. 힙영역의 크기는 고정되어있지 않고 확장되거나 축소될 수 있다.
- 여기서 사용할 수 있는 힙영역의 크기보다 시스템에서 더 많은 힙영역의 크기를 필요로 할 경우OutOfMemoryError가 발생한다.
Method Area
- 모든 JVM쓰레드 사이에 공유되는 영역이다. JVM시작할때 생성된다.
- RuntimeConstantPool, 클래스의 필드와 메서드부분, static오브젝트, 클래스와 인터페이스의 초기화에 사용되는 특수메서드, 생성자들을 저장하는 영역이다.
- 논리적으로는 힙의 일부지만 GC의 대상은 아니다. 메소드영역도 동적으로 할당되는 데이터 영역이다.
- 메소드영역에서 메모리 할당요청을 했을때 메모리공간이 충분하지 않다면 OutOfMemoryError가 발생한다.
- RuntimeConstantPool : MethodArea 내부에 존재하는 영역이다. 상수자료형을 저장하여 참조하고 중복을 막는 역할을 수행한다.
- PC Register : Program Counter Register. 쓰레드가 시작될때 생성된다. 쓰레드가 어떤 명령어로 실행되어야 할지에 대한 기록을 하는부분이다. 현재 수행중인 JVM명령의 주소를 가진다.
- Stack Area : 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터를 저장하기 위한 영역이다. 지역변수, 매개변수, 메소드정보, 연산 중 발생하는 임시데이터, 변수의 주소값등이 저장된다. 메소드 호출시마다 각각의 메소드만을 위한 공간(스택프레임)이 생성되고 메소드 수행이 끝나면 스택프레임이 삭제된다.
- Native Method Stack : 스레드에서 네이티브방식의 메소드가 실행되는 경우 여기에 쌓인다. 여기서 네이티브방식의 메소드는 내부가 C나 어셈블리로 작성된 메소드를 말한다
JVM실행과정
- JVM이 OS로부터 메모리를 할당받고 JVM은 할당받은 메모리를 여러영역으로 나누어 관리한다.
- 자바컴파일러가 소스코드를 읽어들여 바이트코드로 변환시킨다.
- 클래스로더를 통해 class파일들을 JVM으로 로딩한다.
- 로딩된 클래스파일들은 ExecutionEngine을 통해서 해석된다.
- 해석된 바이트코드는 메모리에 배치되고 수행이 이루어진다. 여기 GC가 동작한다.
Static area스태틱 메모리영역
- 하나의 자바파일은 필드,생성자,메서드로 나눠서 구성된다. 그중에서 필드부분에서 선언된 전역변수와 스태틱변수는 스태틱 메모리영역에 저장된다.
Stack area스택 메모리영역
- 메소드안에 있는 변수와 매개변수의 데이터값이 저장되는 공간이 스택영역이다.
- LIFO(Last In First Out)구조로 변수에 새로운 데이터가 할당되면 이전 데이터는 지워진다.
Heap area힙 메모리영역
- 참조형 객체, 배열은 힙영역에 데이터가 저장된다.
- 변수는 스택영역의 공간에서 실제 데이터가 저장된 힙영역의 참조값을 new연산자를 통해서 리턴받는다. → 실제 데이터는 힙영역의 주소값을 스택영역의 객체가 가지고 있다.
관련개념정리
- JRE : JVM이 실행될 수 있는 환경을 만들어준다 → Java Runtime Environment / JRE는 JVM의 한부분. 클래스파일이 주어지면자바가 실행되는 환경을 위한것.
- JDK : 개발할 수 있는 여러툴들을 제공한다 / 프로그램개발을 위한것
어떻게 GC튜닝이 가능한가?
- jvm options에 옵션값을 입력함으로써 가능합니다. GC의 종류에 따라서 옵션값이 다르고 성능에 영향을 미치는 요소가 다릅니다. ex) G1GC의 경우 G1영역을 설정하는 옵션이 별도로 존재함(XX:G1HeapRegionSize=n)
- 튜닝의 목적은 1. GC가 일시적으로 자바프로그램을 중지하는 시간을 줄이는것 2. GC가 돌아가는 총 시간을 줄이는것 3. 위의 두가지목적이 충족되면 힙크기를 줄이기 위한 목적 크게 세가지로 나눠볼 수 있습니다.
출처 - https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/g1_gc_tuning.html#g1_gc_tuning
https://docs.oracle.com/javase/8/docs/technotes/guides/vm/gctuning/ergonomics.html#ergonomics
'Java' 카테고리의 다른 글
동등성과 동일성의 차이 (0) | 2022.05.25 |
---|---|
JVM - java버전별 변경점 (0) | 2022.05.24 |
LocalDateTime to LocalDate 변환 (0) | 2021.09.14 |
unboxing of '*' may produce 'nullpointerexception' (0) | 2021.06.30 |
JSONObject to Map (0) | 2021.04.09 |