GC에 대해서

Red Culture·2021년 7월 16일
0

가비지 컬렉터에 대해서

가비지 컬렉터는 더이상 참조되지 않는 메모리인 가비지를 청소해주는 JVM의 실행 엔진의 한 요소이다. JVM은 new와 같은 연산에 의해 새롭게 생성된 객체들 중에서 더이상 참조되지 않는 객체를 정리하는데 힙 영역의 메모리를 정리한다. 가비지 컬렉션은 메모리를 정리하는 과정이다.

가비지 컬렉션 과정

가비지 컬렉션은 힙 영역의 메모리를 정리하는 과정이기 때문에 메모리를 중단한 채로 진행이 되어야 한다. 그래서 Jvm은 GC를 하기 위해 애플리케이션 실행을 멈추는 stop-the-world를 먼저 실행하고 GC를 실행하는 쓰레드를 제외한 나머지 쓰레드는 작업을 멈춘다.

1) Heap은 Young generation과 Old generation으로 나뉜다. Young generation은 Eden/Survival 0/Survival 1로 세분화된다.
2) GC의 작업은 Young 영역에 대한 Minor GC와 Old 영역에 대한 Major GC로 구분한다.
3) 새로운 객체는 Eden 영역에 생성되고 Eden 영역이 가득차면 Minor GC가 발생되는데 Reference 관계가 없다면 Unreachable Object로 판단하고 eden 영역이 클리어되면 메모리 해제되며 그 외 Reachable Object는 Survival 0으로 이동된다.
4) 기존 Survival 0에 있던 Reachable Object는 Survival 1로 이동된다. Survival 1이 가득차면 Reachable Object들은 Old generation으로 복사된다.
5) Old 영역이 가득차서 Survivor 영역에서 Old 영역으로 Promotion이 불가능할 때 Old 영역에 대한 GC(Major GC)가 실행된다.

  • Reference 관계
    1) Java 메서드 내에서 실행하는 지역 변수 또는 파라미터에 의한 참조
    2) 정적 변수에 의한 참조
    3) JNI에 의해 생성된 객체에 대한 참조

Java 8에서의 Heap과 Metaspace의 분리

Java 8에서 JVM은 Permanent Generation 메모리 영역이 없어지고 Metaspace 영역이 생겼다. 그리고 다음과 같은 변화가 생겼다. (PermGen은 클래스 메타 데이터를 담는 영역으로 Heap 영역에 속했고, 제한된 크기를 가지고 있었다.)

1) Class의 Meta 정보 -> Metaspace 영역으로 이동
2) Method의 Meta 정보 -> Metaspace 영역으로 이동
3) Static Object -> Heap 영역으로 이동
4) 상수화된 String Object (String str = "hello";) -> Heap 영역으로 이동
5) 클래스와 관련된 배열 객체 정보 -> Metaspace 영역으로 이동
6) Jvm 내부 객체와 최적화 컴파일러의 최적화 정보 -> Metaspace 영역으로 이동

  • Static Object의 경우는 메모리에 로딩된 클래스와 클래스 로더가 종료될 때 GC되지 않아 Permanent Generation이 가득차 메모리 누수가 발생되는 문제를 방지하기 위해 Heap 영역으로 옮겨서 최대한 GC의 대상이 되도록 변경되었다.
    -> 간혹 Collection 객체를 static하게 구현해서 값을 계속 추가하다가 perm 영역 가득차서 oom 발생..
static List<Object> list = new ArrayList<>();
  • 수정될 필요가 없는 정보만 Metaspace 영역에 저장하고, Metaspace는 Native 메모리 영역으로 메모리가 부족할 경우 리사이징할 수 있는 구조로 개선되었다.

가비지 컬렉션 알고리즘 종류

  • Serial GC
    -mark-sweep-compact 알고리즘을 사용한다. Old 영역에서 살아있는 객체를 식별하고(Mark), 살아 있는 객체만 남긴다.(sweep) 그 이후에 객체들을 앞부분부터 채워 객체가 존재하는 부분과 존재하지 않는 부분으로 나눈다.(compaction)
  • Parallel GC
    -기본적인 알고리즘은 Serial GC와 같지만, 여러 쓰레드를 통해 GC를 처리한다.
  • Parallel Old GC (Parallel Compationg GC)
    -Serial GC의 sweep 알고리즘 대신 summary 알고리즘을 사용한다. summary 단계에서 앞서 GC를 수행한 영역에 대해 별도 살아있는 객체를 식별한다.
  • Concurrent Mark & Sweep GC
    -Initail Mark 단계에서는 살아있는 객체를 찾고 (stop-the-world 시간이 짧다), 찾은 객체에서 참조하는 객체를 Concurrent(여러 쓰레드가 동시에)하게 따라가는 Concurrent Mark 단계가 수행된다. 그 이후에 stop-the-world가 실행되고 Concurrent하게 remark가 동작한다. stop-the-world 시간을 줄여 애플리케이션 응답 속도를 확보하고자 할 때 사용한다.
  • G1(Garbage First) GC
    -바둑판의 각 영역에 객체를 할당하고 GC를 실행한다. 기존 Young/Old 영역에 대한 개념을 사용하지 하고 객체를 할당한다.

가비지 컬렉션에 의한 시스템 중단을 줄이는 방법

1) 옵션을 변경하여 GC 성능 높이기

  • young 영역과 old 영역의 힙 크기를 높여 GC 빈도를 줄이기
  • 객체의 할당과 promotion을 줄이기

2) 설정을 변경하여 GC 성능 높이기

  • 애플리케이션과 GC 작업을 동시에 진행하기

3) 코드를 변경하여 GC 성능 높이기

  • 불변 객체 사용하기
  • 컬렉션을 활용할 때 사용할 객체의 크기를 명시해주기

*참고 자료
https://code-factory.tistory.com/48
https://velog.io/@hygoogi/%EC%9E%90%EB%B0%94-GC%EC%97%90-%EB%8C%80%ED%95%B4%EC%84%9C

profile
자기 개발, 학습 정리를 위한 블로그

0개의 댓글

관련 채용 정보