Java

JVM

기기디 2022. 5. 24. 00:26

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실행과정

  1. JVM이 OS로부터 메모리를 할당받고 JVM은 할당받은 메모리를 여러영역으로 나누어 관리한다.
  2. 자바컴파일러가 소스코드를 읽어들여 바이트코드로 변환시킨다.
  3. 클래스로더를 통해 class파일들을 JVM으로 로딩한다.
  4. 로딩된 클래스파일들은 ExecutionEngine을 통해서 해석된다.
  5. 해석된 바이트코드는 메모리에 배치되고 수행이 이루어진다. 여기 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