JAVA,객체지향

JAVA /가비지 컬렉터 알고리즘 정리/ 가비지 컬렉터 알고리즘 선택

25G 2023. 9. 6. 17:00

JVM의 가비지 컬렉터 알고리즘 4개

시리얼 가비지 컬렉터

네개중 가장 단순한 알고리즘

애플리케이션이 클라이언트 클래스 머신에서 수행되고 있다면 디폴트 컬렉터 입니다.
시리얼 컬렉터는 힙을 처리하기 위해 단일 스레드를 사용합니다. 마이너나 풀 가비지컬랙션를 사용한다면 애플리케이션스레드는 모두 중지됩니다.
풀 가비지컬랙션가 일어나는 동안에는 올두 제너레이션은 완전히 압축될 것입니다.

시리얼 컬렉터는 -XX:+UseSerialGC 플래그를 통해 사용할 수 있습니다. 대부분의 JVM 플래그와 달리 시리얼 컬렉터는 + 부호를 - 부호로 바꾼다면 비활성화 됩니다.

또는 시리얼 컬렉터가 다폴트인 시스템에서 다른 가비지컬랙션 알고리즘을 명시한다면 비활성화 됩니다.

처리율 컬렉터

서버 클래스 머신 (다중 CPU 유닉스 머신과 64bit JVM)에서 디폴트로 사용되는 컬렉터 입니다.
처리율 컬랙터는 영 제너레이션을 수집할때 스레드를 여러개 사용합니다. 이로 인해 시리얼 컬렉터를 사용하는 것 보다 마이너 가비지 컬렉터가 더 빠릅니다.

그리고 올드 제너레이션을 처리할 때도 여러개의 스레드를 사용하므로 보다 더 빠릅니다.
여러개의 스래드를 사용하기때문에 흔히 병령 컬렉터라고 불립니다.
처리율 컬렉터는 마이너든 풀이든 가비지컬랙션이 일어나는 경우 모든 애플리케이션 스레드를 멈춥니다. 풀 가비지 컬렉션에서는 완전히 올드 제너레이션 영역을 압축합니다.
대부분의 상황에서 처리율 컬렉터는 디폴트 이므로 명시적으로 활성화 시킬 필요는 없습니다.
필요할 때 사용하려면 -XX:+UseParallelGC -XX:+UseParallelOldGC 플래그를 통해 사용 가능합니다.

CMS 컬렉터

CMS 컬렉터는 처리율과 시리얼 컬렉터에서 풀 가비지컬렉션에서 생기는 애플리케이션 스레드의 긴 중지 현상을 해결할려고 설계되었습니다.
CMS도 마이너 가비지컬렉션 동안 애플리케이션 스레드는 전부 중지시키고 여러 개의 스레드로 동작합니다.

하지만 영 제너레이션을 수행하는 데는 다른 알고리즘을 사용합니다.

CMS는 풀 가비지컬렉션 동안 애플리케이션 스레드를 멈추지 않고 주기적으로 올드 제너레이션을 통해 살피고 미사용 객체를 폐기하는 데 하나 이상의 백그라운드 스레드를 사용합니다.

이로 인해 CMS는 저중지 컬렉터가 됩니다. 애플리케이션 스레드는 마이너 컬렉션이 일어나느 동안에만 중지되고 특정 시점에 백그라운드 스레드가 올드 제너레이션을 살피고 미사용 객체를 폐기합니다.

즉 처리율 컬렉터보다 애플리케이션 스레드가 멈춘 시간은 적습니다.

여기서 트레이드 오프는 CPU 사용량이 더 많다는 점입니다. 애플리케이션 스레드가 수행되고 있음에도 동시에 백그라운드 가비지컬렉션 스레드가 동작하므로 CPU가 충분해야 합니다.

게다가 CMS 컬렉터의 백그라운드 스레드는 올드 제너레이션을 살필 때 압축을 하지 않습니다.

이건 힙이 단편화 될 수 있다는 사실을 말하며 CMS 백그라운드 스레드가 작업을 하는데 충분한 CPU를 받지 못하거나 힙이 객체를 할당하는데 단편화가 너무 많이 되거나 해서 올드 제너레이션 영역이 부족하다고 느낀다면 CMS는 시리얼 컬렉터의 동작을 합니다.

이 경우 단일 스레드를 사용해 올드 제너레이션을 비우고 압축하기 위해 모든 애플리케이션 스레드가 중지됩니다.

CMS는 -XX:+UseConMarkSweepGC -XX:+UseParNewGC 플래그를 통해 사용할 수 있습니다. 디폴트는 false 입니다.

G1 컬렉터

G1(Garbage First) 컬렉터는 최소한으로 중지시키며 약 4GB 이상의 큰 힙을 처리하도록 설계되었습니다.

힙을 여러 개의 영역으로 나누지만 여전히 제너레이션 기반의 컬렉터 입니다.

영 제너레이션은 여전히 모든 애플리케이션 스레드를 멈추고 올드 제너레이션이나 서바이버 스페이스로 살아 있는 객체를 옮기는 식으로 동작합니다.

다른 알고리즘과 마찬가지로 이는 여러 개의 스레드를 이용해서 일어납니다.

G1은 동시 병렬 컬렉터로 대부분의 작업을 수행하는 데 애플리케이션 스레드를 중단시킬 필요가 없고 백그라운드 스레드로 올드 제너레이션을 처리합니다.

다만 차이는 올드 제너레이션은 여러 영역으로 나뉘고 G1은 한 영역에서 다른 데로 복사해서 올드 제너레이션에서 객체를 지울 수 있으므로 단편화 현상을 약간 해결합니다. 즉 약간 압축할 수 있습니다.

CMS와 마찬가지로 풀 GC를 피하기 위한 트레이드 오프는 CPU 시간입니다.

애플리케이션 스레드가 수행되고 있더라도 동시에 여러 개의 백그라운드 스레드가 동작해야 하므로 CPU가 더 필요합니다.

G1은 -XX:+UseG1GC 플래그를 통해 사용할 수 있습니다. 디폴트는 false 입니다.

가비지 컬랙션 알고리즘 선택

대부분의 프로그램에서 처리율 컬렉터와 동시 병렬 컬렉터 중에서 선택할 필요가 있습니다. 그 선택의 기준은 애플리케이션의 성능 목표에 따라 다릅니다.
CPU를 추가로 사용할 수 있는 경우에는 동시 병렬 컬렉터를 사용한다면 애플리케이션의 성능을 높일 수 있습니다.
여기서 핵심은 동시 병렬 가비지컬렉터의 백그라운드 처리에 있어서 CPU 이용 가능 여부 입니다.
CPU 100% 를 소비하는 단일 애플리케이션 스레드가 있는 단일 CPU머신의 경우 애플리케이션이 처리율 컬렉터와 실행되면 가비지 컬렉터가 주기적으로 수행되면서 애플리케이션이 정지됩니다.

이 애플리케이션이 동시 병렬 컬렉터와 실행된다면 운영체제는 때로는 애플리케이션을 실행하고 때로는 백그라운드 가비지 커렉터 스레드를 실행할 것입니다.

이 경우 동시 병렬 컬렉터의 경우 백그라운드 스레드의 오버헤드 때문에 성능상에 더 안좋을 것입니다. 이 원칙은 여러개의 애플리케이션 스레드와 여러개의 백그라운드 가비지컬렉터 스레드 여러개의 CPU가 있는 경우에도 적용됩니다.

백그라운드 가비지컬렉터 스레드가 애플리케이션 스레드와 같이 실행되면서 CPU를 받을 수 없다면 처리율 컬렉터 보다 성능상으로 이점이 없을 것입니다.

CMS와 처리율 알고리즘을 쓰는 배치 처리시간

CPU를만힝 쓸수록 CMS 쪽이 유리하고 단일 CPU환경에선 처리율 알고리즘이 더 유리하다. 하지만 단일 CPU 환경이라면 스레드 하나로 애플리케이션과 백그라운드 가비지컬렉터를 사용하기때문에 오버해드가 커지며 비교적 더 비효율 적이다.
한가지 더 생각해 볼 점은 CMS 컬렉터의 경우 백그라운드 가비지컬렉터 스레드가 더 많다고 해서 성능상에 이점을 없을 수 있습니다. 어차피 애플리케이션 스레드는 계속 CPU를 차지하고 있으므로 작업의 수행량은 동일할 것입니다.
즉 CMS 에서 풀 가비지 컬렉터가 일어나지 않을 정도로 백그라운드 가비지 컬렉터 스레드가 처리해주기만 한다면 백그라운드 가비지컬렉터 스레드는 적을 수록 유리합니다.

또한가지 더 처리율을 따져 보자면
클라이언트 갯수가 1개인 경우 CMS는 사용할 수 있는 CPU가 여유있기 때문에 백그라운드 가비지컬렉터 스레드를 돌릴 수 잇고 처리율 가비지컬렉터보다 더 효율적이지만 클라이언트 갯수가 많아지게 되면 자연스럽게 CMS는 백그라운드 스레드를 못쓰게되면서 처리율 가비지컬렉터보다 더 낮은 효율을 보여줍니다.

CMS 와 G1 중 선택

CMS는 힙 사이즈가 4GB 보다 작은 경우에 G1보다 좋은 성능을 낼거라고 예상됩니다. CMS는 G1보다 더 간단한 알고리즘이므로 힙이 작은 경우에 더 빠를 가능 성이 있습니다.
CMS 뱁끄라운드 스레드는 올드 제너레이션 전체를 살펴보면서 해제할 객체를 찾습니다. 그러므로 힙이 작을수록 성능이 좋습니다.
하지만 G1의 경우 올드 제너레이션 영역을 분담해서 처리하기 때문에 큰 힙이라면 G1이 더 빠를것입니다.