본문 바로가기
Java

[Java] 가비지 컬렉션(Garbage Collection, GC)과 알고리즘

by parkjp 2017. 9. 8.

 

1. 가비지 컬렉션 (Garbage Collection, GC)란?

 

 예전의 전통적인 언어인 C 등은 malloc(), free() 등을 이용해서 메모리를 할당하고, 일일이 그 메모리를 거둬야 했다. 하지만 자바 언어에서는 GC 기술을 사용하여 개발자를 메모리 관리로부터 좀 더 자유롭게 해주었다. GC 즉 가비지 컬렉션은 자바 애플리케이션에서 사용하지 않는 메모리를 자동으로 거둬들이는 기능을 말한다.

 

 

2. 메모리 영역과 JVM의 GC 관리

 

* 각 영역 별 설명은 이전 글을 참조하기 바란다.

이전 글 : 2017/09/08 - [Java] - [Java] JVM의 구조와 이해

 

 

- Minor GC 

 

 New/Young 영역의 GC를 Minor GC라고 부른다. Eden 영역은 자바 객체가 생성되자마자 저장되는 곳이다. 이렇게 생성된 객체는 Minor GC가 발생할 때 Survivor 영역으로 이동된다. 위 그림처럼 Survivor 영역은 Survivor1과 Survivor2로 나뉘는데 Minor GC가 발생하면 Eden과 Survivor1에 활성 객체를 Survivor2로 복사한다. 그리고 활성이 아닌 객체는 자연히 Survivor1에 남아있게 되고, Survivor1과 Eden 영역을 클리어한다. 

 

다음번 Minor GC가 발생하면 같은 원리로 Eden과 Survivor2 영역에서 활성 객체를 Survivor1으로 복사한다. 계속 이런 방법을 반복적으로 수행하면서 Survivor 영역에서 오래된 객체는 Old 영역으로 옮기게 된다.

 

이런 방식을 Copy & Scavenge라고 하며, 속도가 매우 빠르고 작은 크기의 메모리를 콜렉팅하는데 아주 효과적이다. Minor GC는 자주 일어나기 때문에 걸리는 시간이 짧은 알고리즘이 적합하다.

 

- Full GC

 

 Old 영역의 가비지 콜렉션을 Full GC라고 한다. Full GC에 사용되는 알고리즘은 Mark & Compact라는 알고리즘이다. 이 알고리즘은 전체 객체들의 참조를 확인하면서 참조가 연결되지 않은 객체를 표시한다. 이 작업이 끝나면 사용되지 않는 객체를 모두 표시하고 이 표시된 객체를 삭제한다. (실제로는 표시된 객체(사용하지 않는 객체)로 생기는 부분을 사용하는 객체로 메꾸어 버리는 방법이다)

 

Full GC는 속도가 매우 느리며, Full GC가 일어나는 도중에는 순간적으로 자바 애플리케이션이 멈춰 버리기 때문에 애플리케이션의 성능과 안정성에 아주 큰 영향을 준다.

 

 

3. GC 알고리즘

 

 위에서 언급한 기본적인 GC 방법 외에도 다양한 GC 알고리즘이 있다.

 

A. Default Collector

 

전통적인 GC 방법이다. Minor GC에서 Scanvenge를, Full GC에서 mark & Compact 알고리즘을 사용하는 방법이다.

 

B. Parallel GC

 

 Parallel GC는 Minor GC를 동시에 여러 개의 스레드를 이용해서 GC를 수행하는 방법으로, 하나의 스레드를 이용하는 것보다 훨씬 빨리 GC를 수행할 수 있다. 하지만 이 방법은 최소한 4 CPU의 256M 정도의 메모리를 가진 하드웨어에서 사용해야 유용하다.

 

Parallel GC는 크게 두 가지 종류의 옵션을 가지고 있는데, Low-pause 방식과 Throughput 방식의 GC 방식이 있다. Low-pause 방식은 Concurrent GC 방법과 함께 사용할 수 있으며, 빨리 GC를 수행하는 것보다 GC가 발생할 때 애플리케이션이 멈추는 현상(pause)을 최소화하는데 역점을 두었다. Throughput 방식에서는 Old 영역을 GC할 때는 Mark & Compact 방법만을 사용하게 되어있으며, Minor GC가 수행될 때 될 수 있으면 최대한 신속하게 수행하도록 역점을 두었다.

 

이 외에도 Parallel GC는 수행할 때 사용되는 스레드의 수를 지정할 수 있다.

 

C. Concurrent GC

 

 이 방법은 Full GC에 의해서 애플리케이션이 멈춰버리는 현상을 최소화하기 위한 GC 방법이다. Full GC에 소요되는 작업을 애플리케이션을 멈추고 진행하는 것이 아니라 일부는 애플리케이션이 돌아가는 단계에서 수행하고 최소한의 작업만을 애플리케이션이 멈췄을 때 수행하는 방법으로, 멈추는 시간을 최소화한다.

 

D. Incremental GC (Train GC)

 

 이 방법 또한 Concurrent GC와 비슷하게 의도 자체는 Full GC에 의해 애플리케이션이 멈추는 시간을 줄이고자 하는데 있다. 하지만 이 방법은 Minor GC가 일어날 때마다 Old 영역을 조금씩 GC를 해서 Full GC가 발생하는 횟수나 시간을 줄이는 방법이다.

 

Incremental GC를 사용하는 방법은 JVM 옵션에 -Xinc 옵션을 사용하면 된다. 해당 GC는 많은 자원을 소모하고 Minor GC를 자주 일으킨다. 또한 이 방법을 사용한다고 해서 Full GC가 없어지거나 그 횟수가 획기적으로 줄어드는 것은 아니다. 오히려 느려지는 경우도 있으니 반드시 테스트 후에 사용해야 한다.

 

 

Default GC 이외의 알고리즘은 애플리케이션의 형태나 하드웨어의 사양, 그리고 JVM의 버전에 따라서 차이가 매우 크다. 따라서 미리 충분한 테스트를 거쳐 검증 후에 사용하여야 한다.

 

 

 

 

 

 

참조 저서 : 조병욱(조대협), 대용량 아키텍처와 성능 튜닝, 프리렉 출판, 391쪽

반응형

'Java' 카테고리의 다른 글

[Spring Boot] Logging 설정하기 (로그 설정)  (0) 2023.07.21
SOLID (객체 지향 설계)  (0) 2022.02.21
[Spring] JPA Specification Example  (0) 2019.04.02
[Java] JVM의 구조와 이해  (0) 2017.09.08
[Java] 람다 표현식, 람다란?  (0) 2017.09.06