[Java] JVM의 GC

Kyunghwan Ko·2022년 11월 27일
0

Java

목록 보기
1/14
post-thumbnail

JVM(Java Virtual Machine)

  • 운영체제의 메모리 영역에 접근하여 메모리를 관리하는 프로그램
  • 메모리 관리, GC 수행

GC(Garbage Collector)

  • Garbage collection was invented to simplify-manual memmory management
  • 동적으로 할당한 메모리 영역 중 사용하지 않는 영역을 탐지하여 해제하는 기능

Stack, Heap

Stack

  • 정적으로 할당한 메모리 영역
  • Primitive Type의 데이터가 값과 함께 할당, Heap영역에 생성된 Obejct타입의 데이터의 참조 값 할당

Heap

  • 동적으로 할당한 메모리 영역
  • 모든 Object 타입의 데이터가 할당(최상위 조상인 Object 클래스를 상속받은 클래스의미), Heap영역의 Object를 가리키는 참조변수가 Stack에 할당

코드

public class Main{
	public static void main(String[] args){
    	int num1 = 10;
        int num2 = 5;
        int sum = num1 + num2;
        String name = "던";
        
        System.out.println(sum);
        System.out.println(name);
    }
}

위와 같이 작성했을 때, Local Variable(지역변수)들 중

  • Primitive 타입 변수들은 stack에 호출순서대로 LIFO구조로 저장됨
  • Class 타입 변수(ex. String)는 Heap영역에 할당됨

이후 함수의 맨 마지막 } 를 만나서 함수가 종료되면 Stack에 있는 Local Variable은 다 pop되고 Heap영역에 Class 타입의 변수는 남아있게 된다.

이처럼 던: String 변수는 Unreachable Object(참조되지 않는 객체)가 되어서 GC의 대상이 된다.

GC 과정(Mark and Sweep)

참조되지 않는 객체를 찾아서 삭제하는 것이 목표!

  1. [Mark] GC가 Stack의 모든 변수를 스캔하면서 각각 어떤 객체를 참고하고 있는지 찾아서 마킹한다.
  1. [Mark] Reachable Object가 참조하고 있는 객체도 찾아서 마킹한다.
  1. [Sweep] 마킹되지 않은 객체를 Heap에서 제거한다.

앞서 설명을 참고해서 위 그림을 보면 던: String이 Unreachable Object이기 때문에 GC에 의해 제거될 것이다.

Heap

  • Heap은 New Generation과 Old Generation으로 구성됨
  • New Generation에는 Eden, Suvival 0, Suvival 1 영역이 있음

Step 1. 새로운 객체 Eden영역에 할당됨

새로운 객체가 생성될 때 Eden영역에 할당됩니다.

Step 2. Eden -> Survival 이동(Minor GC)

위 사진처럼 Eden이 가득차게 되면 GC가 발생하게 됩니다.(Minor GC)
그래서 Eden영역에서 Mark and Sweep과정이 일어납니다.
여기서 살아남은 객체는 Survival 영역으로 이동합니다.(Unreachable 객체는 메모리에서 해제)
(Survival 영역 중 이미 객체가 존재하는 곳으로 우선적으로 이동)

따라서 GC는 Survival 0 | Survival 1 둘 중 한 영역은 계속 비어있도록 유지한다

Step 3. Survival -> 다른 Survival로 이동(Minor GC)

앞선 Step1, 2 과정을 반복하면서 한 Survival 영역이 가득차게 된다면 GC가 발생하게 됩니다.(Minor GC)
그래서 그 Survival 영역에서 Mark and Sweep과정이 일어납니다.
여기서 살아남은 객체는 다른 Survival 영억으로 이동합니다.(Unreachable 객체는 메모리에서 해제)

이때, 다른 Survival 영역으로 이동한 객체는 Age값이 증가합니다.
(그래서 색깔이 좀 더 진하게 표현했습니다.)

Step 1, 2과정을 진행하다가 아래와 같이 한 Survival 영역이 가득 찼다면,

그 Survival 영역에서 Minor GC가 동작해서 Mark & Sweep 과정이 일어나고
다시 Step 3 과정을 진행한다.

(다른 Survival 영역으로 옮기고 Age가 증가한 모습을 볼 수 있습니다)

Step 4. Old Generation으로 이동(Promotion)

위 Step 1, 2, 3을 반복하다가 Age값이 특정 값 이상이 되면 Old Generation 영역으로 옮겨진다.

Step 5. Old Generation에서 GC 발생(Major GC)

위 Step 1, 2, 3, 4를 반복하다가 Old Generation이 가득차게 된다면
Old Generation에서 GC가 발생합니다.

위 과정이 반복되면서 GC가 메모리를 관리한다.

GC의 종류

1. Serial GC

  • GC를 처리하는 Thread가 1개
  • CPU 코어가 1개만 있을 때 사용하는 방식
  • Mark-Compact collection 알고리즘 사용

Mark-Compact


Mark and Sweep과정에서 Compact과정이 추가된 것이다 Sweep을 하고 나서 살아남은 객체의 메모리상 물리적 위치가 군데군데 위치하게 되었을 때,
효율적으로 메모리 관리하고 메모리 파편화를 방지하기 위해 메모리의 특정위치에 모이게 해 관리한다.

2. Parallel GC

  • GC를 처리하는 Thread가 여러개
  • Serial GC보다 빠르게 객체를 처리할 수 있음
  • Parallel GC는 메모리가 충분하고 코어의 개수가 많을 때 사용하면 좋음

3. Concurrent Mark Sweep GC (CMS GC)

Stop-the-world

  • GC 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것
  • stop-the-world가 발생하면 GC를 실행하는 Thread를 제외한 나머지 Thread는 모두 작업을 멈춤
  • GC 작업을 완료한 이후에 중단한 작업을 다시 시작함
  • 앞선 GC들 보다 Stop-the-World 시간을 줄인 GC
  • 응답 속도가 중요한 애플리케이션에서 사용됨
  • Inital Mark에선 GC과정-1에 해당하는 Mark과정을 진행(Stack 모든 변수 스캔)
  • Concurrent mark에선 Inital Mark에서 마킹한 객체가 어떤 객체를 참조하고 있는지
    객체그래프를 타고 가면서 계속해서 마킹하는 과정
  • Remark는 concurrent mark과정에서 application도 같이 수행되기에 그 동안에 새롭게 발생한 Unreachable object가 존재하는지 다시 마킹하는 과정
  • Concurrent Sweep 과정을 통해 애플리케이션과 동시에 수행되면서 Sweep진행

장점(Pros)

  • Stop-the-World 시간이 짧음
  • 애플리케이션의 응답 시간이 빨아야 할 때, CMS GC를 사용한다.

단점(Cros)

  • 다른 GC방식보다 메모리와 CPU를 더 많이 사용한다.(애플리케이션과 병렬적으로 진행하기 때문)
  • Compaction 단계까 제공되지 않는다.

4. G1 GC

  • 각 영역을 Region 영역으로 나눈다(New, Old Generation으로 묶어 관리하지 않고 각각 나눈다 -> 초록색: Eden, 파란색: Survival)
  • GC가 일어날 때, 전체 영역(Eden, Survival, Old Generation)을 탐색하지 않는다.
    (Region이 가득찬 부분만 탐색)
  • 바둑판의 각 영역에 객체를 할당하고 GC를 실행함
    그러다가 해당 영역이 꽉 차면 다른 빈 영역에 객체를 할당하고 GC를 실행

특징

  • G1 GC는 STW(Stop-The-World)시간이 짧음
  • Compaction을 제공함

참고

[10분 테코톡] 👌던의 JVM의 Garbage Collector

profile
부족한 부분을 인지하는 것부터가 배움의 시작이다.

0개의 댓글