본문 바로가기
공부이야기/Java

[Java] JVM이란? 그리고 Garbage Collector

by coderoom 2021. 4. 28.

 

 

 

 

 

JVM(Java Virtual Machine) 이란? 

 

자바 애플리케이션을 클래스 로더를 통해 읽어 들여 이를 자바 API와 함께 실행하는 역할을 한다.

또한, JAVA와 OS 사이에서 중개자 역할을 수행하여 JAVA가 OS에 구애받지 않고 재사용을 가능하게 해준다.

그리고 가장 중요한 메모리 관리, Garbage Collection을 수행한다.

 

 

 

JVM의 구성

 

Class Loader (클래스 로더)

자바 컴파일러에 의해 컴파일된 바이트코드(.class파일)을 JVM의 Runtime Data Area로 로드하는 역할을 한다.

이는 자바 애플리케이션이 실행 중일때 (runtime) 수행된다.

 

Execution Engine (실행 엔진)

클래스 로더가 로드한 바이트코드를 실행시킨다. 이때 바이트코드(.class)는 인간에게 쉬운 방식으로 작성되어 있어 이를 기계어로 변경한다. 실행 방식은 두 가지이다.

 

  • Interpreter
    • 명령어 단위로 읽어서 실행하는 방식. 명령어 단위로 한 줄 씩 수행하기 때문에 느리다.
  • JIT Compiler
    • 인터프리터의 단점을 보완하기 위해 도입된 방식. 적절한 시점에 바이트코드 전체를 컴파일하여 네이티브 코드로 변경해서 직접 실행하는 방식이다. 변경된 네이티브 코드는 캐시에 보관하기 때문에 한번 컴파일되면 이후엔 빠르게 수행되지만 인터프리팅 보다는 훨씬 오래 걸리기 때문에 한 번만 실행되는 코드라면 인터프리팅 방식이 더 유리하다.

 

Runtime Data Area

프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간이다.

 

 

 

JVM 수행 과정

 

  1. 프로그램이 실행되면 JVM은 OS로부터 필요한 메모리를 할당받는다. 

  2. 자바 컴파일러(javac)가 자바 소스코드(.java)를 읽어들여 자바 바이트코드(.class)로 변환시킨다.

  3. 클래스 로더를 통해 바이트코드를 JVM의 Runtime Data Area로 로드한다.

  4. 로딩된 바이트코드는 실행 엔진을 통해 해석된다.

  5. 해석된 바이트코드는 실행 엔진의 각 영역에 배치되어 수행된다.
    이때 실행 엔진에 의해 GC와 Thread 동기화가 이루어진다.

 

 

Runtime Data Area

프로그램을 수행하기 위해 OS로부터 할당받은 메모리 공간

https://asfirstalways.tistory.com/158

 

 

Method Area (메소드 영역)

모든 Thread 공유. JVM이 읽어들인 클래스와 인터페이스에 대한 정보를 저장하는 공간. Runtime Constant Pool이라는 별도의 공간이 존재하는데 여기엔 각 클래스와 인터페이스의 상수, 메소드, 필드에 대한 모든 레퍼런스를 담겨 있으며 이를 통해 이미 있는 메소드나 필드의 중복을 막는다.

 

  • 필드 정보
    • 멤버 변수의 이름, 데이터 타입, 접근 제어자에 대한 정보
  • 메소드 정보
    • 메소드의 이름, 리턴 타입, 파라미터, 접근 제어자에 대한 정보
  • 타입 정보
    • class/interface 여부, 속성, 전체 이름, super class의 전체 이름

 

Heap Area (힙 영역)

모든 Thread 공유. new 키워드로 생성된 객체와 배열이 생성되는 공간. 메소드 영역에 로드된 클래스들만 객체로 생성할 수 있으며 GC의 동작 대상이다.

 

Stack Area (스택 영역)

지역 변수(local variable), 파라미터, 리턴 값, 연산에 사용되는 임시 값 등 임시로 할당되었다가 메소드를 빠져나가면 바로 소멸되는 특성의 데이터가 저장되는 공간. 메소드 호출 시 마다 각각의 스택 프레임이 생성되고 수행이 끝나면 프레임 별로 삭제가 된다.

 

PC Register (PC 레지스터)

Thread가 생성될 때 마다 생성되는 영역으로 현재 쓰레드가 실행되는 부분의 주소와 명령을 저장한다. 

 

Native method stack

자바 외 언어로 작성된 네이티브 코드를 위한 메모리 공간. JNI(Java Native Interface)를 통해 호출되는 C/C++ 등의 코드를 수행하기 위한 스택이다.

 

 

 

 

Heap Area

new 키워드로 생성된 객체와 배열이 생성되는 공간이며 GC의 동작 대상이다.

Java 8 이후엔 Permanent Generation이 Metaspace로 변경되었다.

기능은 비슷하지만, 주요 차이점은 동적으로 사이즈를 바꿀 수 있다는 점.

https://asfirstalways.tistory.com/159

 

 

 

 

 


 

 

Garbage Collection

힙 내의 객체 중에서 Garbage를 찾아내고 찾아낸 Garbage를 처리해서 힙의 메모리를 회수한다. 여기서, 참조되고 있지 않은 객체(Instance)를 Garbage라고 하며 객체가 Garbage인지 아닌지 판단하기 위해 reachability라는 개념을 사용한다. 어떤 힙 영역에 할당된 객체가 유효한 참조가 있으면 reachability, 없다면 unreachability로 판단한다. 객체 간의 참조로 참조 사슬이 형성되는데, 이 중에 최초에 참조한 것을 Root Set이라고 칭한다.

 

 

참조 경우

  • 힙 내의 다른 객체에 의한 참조
  • Java 스택, 즉 Java 메소드 실행 시에 사용하는 지역변수와 파라미터들에 의한 참조 Root Set
  • 네이티브 스택에 의해 생성된 객체에 대한 참조 Root Set
  • 메소드 영역의 정적 변수에 의한 참조 Root Set

 

 

객체가 GC의 대상이 되었다고 바로 소멸되는 것은 아니다. 빈번한 GC는 시스템에 부담이 될 수 있기 때문이다. 따라서 GC의 실행 타이밍은 별도의 알고리즘을 기반으로 계산되며, 이를 기반으로 GC가 수행된다.

 

 

 

Minor GC

Young Generation에서 일어나는 GC

 

  1. 최초에 객체가 생성되면 Eden영역에 생성된다.
  2. Eden 영역에 객체가 가득차게 되면 첫 번째 GC가 일어난다.
  3. Survivor 0 영역에 Eden 영역의 메모리가 그대로 복사된다. 
    그리고 Survivor 0 영역을 제외한 다른 영역의 객체를 제거한다.
  4. 시간이 지나 Eden 영역도 다시 가득 차고 Survivor 0 영역도 가득 차게 된다면, Eden 영역에 생성된 객체와 Survivor 0 영역에 생성된 객체 중에 참조되고 있는 객체가 있는지 검사한다.
  5. 참조되고 있는 객체만 Survivor 1 영역에 복사된다.
    그리고 Survivor 1 영역을 제외한 다른 영역의 객체를 제거한다.
  6. 위의 과정 중에서 일정 횟수 이상 참조되고 있는 객체들을 Survivor 1 영역에서 Old 영역으로 이동시킨다.
    계속 반복하며, Survivor 1 영역까지 꽉 차기 전에 계속해서 Old 영역으로 비운다.

 

Major GC

Old 영역에서 일어나는 GC. Old 영역에 있는 참조가 있는 객체들을 표시하고 그 외의 객체들을 모두 제거하게 된다.

시간이 오래 걸리고 실행 중인 프로세스가 정지된다. 이를 'stop-the-world'라고 하는데 Major GC가 발생하면 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춘다.

 

  1. Old 영역에 있는 모든 객체들을 검사하며 참조되고 있는지 확인한다.
  2. 참조되지 않은 객체들을 모아 한번에 제거한다.

 

 

 

 

 

 

 

참고 링크

 

 

 


 

 

 

 

댓글