Garbage Collection

최창효·2022년 2월 12일
0

자바 이해하기

목록 보기
2/8
post-thumbnail
post-custom-banner

GC란

JVM의 Heap영역에서 사용하지 않는 객체를 삭제하는 프로세스 입니다.
GC가 주기적으로 사용하지 않는 객체를 삭제해 줘서 자바는 메모리를 효율적으로 사용할 수 있게 됩니다.
사용하지 않는다고 판단되는 객체를 알아서 없애주기 때문에 프로그래머는 이를 신경쓰지 않아도 됩니다.
대신 GC의 대상이 되는 객체를 프로그래머가 임의로 메모리에서 삭제하는 것도 불가능합니다.

???: 엄마 저번에 내방에 있던 그거 어디갔어
GC: 그거 니가 안쓰길래 엄마가 버렸어

???: 엄마 이거 잘 안쓰는거 같은데 버릴까?
GC: 엄마가 알아서 버릴께 너는 이런거 신경쓸 시간에 공부나 해

GC의 수거대상 - Unreachable한 Object들

어떤 객체에 유효한 참조가 존재한다면 Reachable, 그렇지 않다면 Unreachable하다고 표현합니다.

GC Roots에서부터 참조가 유효한지 검사합니다.

  • GC Roots가 될 수 있는 것들

    • stack영역의 데이터들
    • method영역의 static 데이터들
    • JNI에 의해 생성된 객체들
  • GC Roots가 참조하는 Object에 의해 참조되고 있는 다른 Object도 Reachable한 상태입니다.

GC의 동작 순서 - Mark and Sweep

Mark

GC Root로부터 모든 변수를 스캔하면서 Reachable한지, Unreachable한지를 판단합니다.

Sweep

Unreachable한 객체를 힙에서 제거합니다.

Compact

Sweep후에 듬성듬성 남아있는 객체들을 Heap의 앞쪽으로 밀어 메모리가 할당된 부분과 그렇지 않은 부분의 경계를 명확히 나눕니다.
알고리즘에 따라 Compact과정은 없기도 합니다.
Compact로 인해 Stop-the-world가 발생합니다.

힙의 구조

힙은 크게 Young Generation, Old Generation, 그리고 meta space영역으로 구분됩니다.

  • Young Generation: 새로운 객체들이 할당되는 공간으로 다시 에덴,서바이버0,서바이버1공간으로 나뉩니다.
  • Old Generation: Young Generation에서 오래 살아남은 객체들이 보관되는 공간입니다.
  • meta space: GC에 필요한 클래스와 메서드의 요약 정보가 존재하는 공간입니다.

GC는 언제 일어날까?

특정 공간이 다 차면 GC가 실행됩니다.

  1. Eden이 다 차면 발생(Minor GC)

  2. Survivor가 다 차면 발생(Minor GC)

  3. Old generation이 다 차면 발생(Major GC)

GC가 일어나는 과정

  1. 객체들이 eden에 쌓입니다.
  2. eden이 가득차면 Minor GC가 발생합니다.
  3. 살아남은 객체들을 survivor0 또는 survivor1영역으로 보내지고, age가 1 증가합니다.
  4. 이러한 과정이 반복됩니다. 이때 survivor영역은 번갈아가며 한 곳만 사용됩니다.
  5. 살아남은 객체의 age가 계속 증가하여 임계치에 도달하면 해당 객체는 Old Generation에 보내집니다.
  6. 이러한 과정에서 Old Generation영역이 가득 차면 Major GC가 발생합니다.

단편화

메모리 단편화란 RAM에서 메모리의 공간이 작은 조각으로 나뉘어져 사용 가능한 메모리가 충분히 존재하지만 할당이 불가능한 상태를 말합니다.

GC과정에서 survivor영역을 옮겨다니면 공간이 정리되기 때문에 단편화를 해결할 수 있습니다.

compact vs survivor01에 옮겨담기 차이가 뭘까?

Minor GC와 Major GC(Full GC)를 나눈 이유

GC 설계자들이 다음 두 가지를 가정했기 때문입니다.
1) 대부분의 객체는 금방 접근 불가능한 상태(unreachable)가 된다.

  • 금방 garbage가 되기 때문에 Minor GC가 따로 존재해서 자주 발생하는 게 효율적이다.

2) 오래된 객체에서 젊은 객체로의 참조는 아주 드물게 나타난다.

  • 둘의 연관성이 적기 때문에 하나는 Minor하게 자주, 하나는 Major로 아주 가끔 처리해도 괜찮다.
  • 하지만 오래된 객체에서 젊은 객체로의 참조가 발생한다면?
    • 그럴 때에는 card table에 정보를 기록하고 Minor GC를 할 때 old영역을 스캔하지 않고 card table을 통해 GC 대상인지를 확인합니다.

Stop-the-world란?

GC를 실행하기 위해 JVM이 애플리케이션 실행을 멈추는 것을 말합니다.
Stop-the-world가 발생하면 가비지 컬렉터를 실행하는 쓰레드를 제외한 나머지 쓰레드는 모두 작업을 멈춥니다.
가비지 컬렉터 작업이 완료되면 멈췄던 쓰레드들이 다시 실행됩니다.

GC의 성능을 향상시키는 방법

GC의 성능향상 방법으로는 크게 Young 영역과 Old 영역의 힙 크기를 알맞게 조정하는 방법객체의 할당이나 Survivor영역,Old영역으로의 이동을 줄이는 방법이 있습니다.

  • 힙의 크기를 변경하는 방법은 heap의 크기를 늘리면 GC를 수행하는 시간이 오래걸리게 되고, heap의 크기를 줄이면 GC를 자주 수행하게 되는 상충관계가 존재하기 때문에 경우에 따라 GC의 성능이 향상되지 않을 수도 있습니다.
  • Minor GC에게는 힙의 크기보다 객체의 생존여부가 더 중요합니다. 즉, 불필요한 객체를 만들지 않는 게 곧 GC의 성능을 향상시키는 가장 좋은 방법이라 말할 수 있습니다.

객체의 낭비를 줄이는 방법

Collection의 크기를 잘 설정하라

  • 대표적으로 ArrayList의 경우 길이가 가변적이지만 내부적으로는 여전히 배열을 사용하고 있습니다.
    • ArrayList의 길이를 확장시키는 Doubling과정은 길이가 2배인 새로운 배열에 옮겨담는 방식이기 때문에 이전 배열은 가비지 상태가 되어버립니다.
    • 그렇기 때문에 배열의 크기를 최대한 잘 예측해 설정한다면 객체의 낭비를 줄일 수 있습니다.

Stream을 사용해라

  • Stream은 내부적으로 Buffer를 두고 있어 가비지 생성을 줄여줍니다.

String을 잘 활용해라

  • 동일한 문자열이라면 String Constant Pool을 활용하는게 더 효율적입니다.
  • String의 연산은 대부분 내용의 변경하는 것이 아니라 새로운 문자열을 할당하는 경우가 많습니다.
    • 새로운 문자열을 할당하면 기존의 문자열은 가비지 상태가 되어버립니다.
    • 이러한 경우 String대신 StringBuilder를 사용하면 낭비를 줄일 수 있습니다.

Immutability를 활용해라

  • 불변의 객체들은 이들을 담는 컨테이너가 존재합니다.
    • 해당 컨테이너가 그대로 존재한다는 건 컨테이너 속 객체들이 여전히 참조되고 있다는 뜻이므로 GC가 검사를 스킵하고 넘어갈 수 있게 됩니다.

불필요한 객체 생성을 피해라

  • 기존의 객체를 적절히 재활용 해 사용하는 것도 객체의 낭비를 줄이는 좋은 방법 중 하나입니다.

GC의 종류

Serial GC

GC를 처리하는 쓰레드가 1개(싱글 쓰레드)
다른 GC에 비해 stop the world시간이 길다
Mark-Compact 알고리즘 사용

Parallel GC

Serial GC를 개선
java8의 default GC
Minor GC를 멀티 쓰레드로 수행
Serial GC보다 stop the world시간이 짧다

Parallel Old GC

Parallel GC를 개선
Major GC도 멀티 쓰레드로 수행
Mark-Summary-Compact 알고리즘을 사용

CMS GC(Current Mark Sweep)

Reachable한 객체를 한번에 찾지 않고 순차적으로 찾는 게 특징
GC를 처리하는 쓰레드는 하나지만 나머지 쓰레드들은 작업을 계속 진행하고 있음
compact 과정이 없음 -> 메모리 단편화 문제가 살짝 아쉬움

G1 GC(Garbage First)

CMS GC를 개선
java9이상의 default GC
Heap영역을 (YG,OG로 물리적으로 나누지 않고)일정한 크기의 Region으로 나눔
전체 Heap이 아닌 할당된 Region에 대해서만 Marking을 함(Region단위로 탐색함)
Garbage만 있는 Region을 수거해 감
compact 과정이 있음

GC종류에 대한 상세한 설명은 여기에서 진행하겠습니다.

References

profile
기록하고 정리하는 걸 좋아하는 개발자.
post-custom-banner

0개의 댓글