프로그래밍 언어/JAVA

[트러블슈팅] 자주 발생하는 Full GC

투칼론 2023. 3. 14. 13:45
반응형

(원문) https://poonamparhar.github.io/frequent_full_gc/

 

Java 애플리케이션의 최적 성능은 빈번한 전체 가비지 수집 주기로 인해 심각하게 방해받을 수 있습니다. 이 게시물에서는 반복되는 Full GC로 이어질 수 있는 몇 가지 상황과 이를 인식하고 처리하는 방법에 대해 설명합니다.

 

전체 GC가 자주 발생하는 주요 원인 중 하나는 애플리케이션의 JVM 관리 메모리 공간이 잘못 구성되었기 때문입니다. Java 힙의 크기가 Java 객체의 라이브 세트보다 작거나 Metaspace가 너무 작게 구성되었을 수 있습니다.

Misconfiguration of Memory Spaces

Java 힙, 특히 이전 세대의 사용률과 Metaspace를 모니터링하여 이러한 공간에 대한 애플리케이션의 요구 사항을 이해해야 합니다. 발생하는 전체 GC가 공간을 차지할 수 없는 경우 크기 구성 문제일 수 있습니다. Java 힙 또는 Metaspace가 애플리케이션의 요구 사항보다 작게 구성되었을 수 있습니다. Java 힙 또는 메타스페이스 크기를 각각 늘리고 더 큰 크기를 사용하여 애플리케이션을 다시 실행하십시오. 더 큰 힙 또는 메타스페이스 크기에서도 오류가 지속되고 메모리 증가가 계속되는 경우 메모리 누수가 있을 수 있습니다.

 

Full GC가 자주 발생하는 또 다른 원인은 개체가 Young Generation에서 Old Generation으로 너무 일찍 승격되는 것일 수 있습니다. 이 경우 젊은 세대의 크기를 늘리고 수명이 짧은 인스턴스를 마이너 컬렉션과 함께 수집하도록 허용하면 빈번한 전체 GC 상황을 피하는 데 도움이 될 수 있습니다.

Memory Leaks

메모리 누수는 특정 인스턴스나 클래스가 의도하지 않게 메모리에 유지될 때 발생합니다. 애플리케이션에 메모리 누수가 있음을 확인한 후 다음 단계는 해당 메모리 누수를 유발하는 인스턴스 또는 클래스를 식별하는 것입니다. 메모리 누수 진단에는 힙 히스토그램과 힙 덤프가 매우 유용합니다. 힙 히스토그램은 Java 힙에 대한 빠른 보기를 제공하고 힙에서 무엇이 증가하고 있는지 이해하는 데 도움이 됩니다. 힙 덤프는 메모리 누수 문제 해결에 가장 유용한 진단 데이터입니다. 응용 프로그램이 메모리 증가를 나타내기 시작하기 전과 후에 주기적으로 힙 덤프를 수집합니다.

 

Eclipse MAT 또는 기타 힙 덤프 분석 도구를 사용하여 수집된 힙 덤프를 분석할 수 있습니다. 시간 경과에 따라 Java 힙에서 증가하는 개체를 확인하려면 수집된 힙 덤프에서 다양한 유형의 인스턴스 수를 비교하십시오. 마찬가지로 메타스페이스에서 공간을 회수하기 위해 자주 발생하는 GC의 경우 가장 많이 성장하는 클래스, 특히 여러 번 로드해서는 안 될 것으로 의심되는 중복 클래스를 찾습니다. 그런 다음 해당 인스턴스 및 클래스의 GC 루트를 찾으면 메모리 누수의 원인을 찾을 수 있으므로 빈번한 Full GC를 방지할 수 있습니다.

Full GCs with ParallelGC

병렬 가비지 수집기는 노력의 이득이 적고 Java 힙이 거의 가득 찬 경우에도 빈번한 연속 Full GC를 호출하여 Java 힙의 공간을 확보하려고 지속적으로 시도할 수 있다는 점에 유의하는 것이 중요합니다. 이것은 애플리케이션의 성능에 영향을 미치고 시스템이 다시 바운스되는 것을 방지할 수 있습니다. 이 상황은 -XX:GCTimeLimit 및 -XX:GCHeapFreeLimit JVM 옵션의 값을 조정하여 피할 수 있습니다.

 

GCTimeLimit는 총 시간의 백분율로 GC가 소비할 수 있는 시간의 상한을 설정합니다. 기본값은 98%입니다. 이 값을 줄이면 가비지 수집에 소요될 수 있는 허용 시간이 줄어듭니다. GCHEapFreeLimit는 최대 힙의 백분율로 표시되는 가비지 수집 후 여유 공간의 하한을 설정합니다. 기본값은 2%입니다. 이 값을 늘리면 GC에서 더 많은 힙 공간을 회수해야 함을 의미합니다. 이전 5개의 연속 GC(마이너 또는 전체일 수 있음)가 GC 비용을 GCTimeLimit 미만으로 유지할 수 없고 GCHEapFreeLimit 공간을 확보할 수 없는 경우 전체 GC 후에 OutOfMemoryError가 발생합니다.

 

예를 들어 GCHeapFreeLimit를 8%로 설정하면 힙의 8% 이상을 회수할 수 없고 5회 연속 GC에 대해 GCTimeLimit를 초과할 때 가비지 수집기가 연속 전체 GC를 호출하는 루프에 빠지지 않도록 할 수 있습니다. 

System.gc()

전체 GC 로그 항목의 System.gc() 문자열 모양은 해당 GC가 java.lang.Runtime.gc() 또는 System.gc()에 대한 명시적 호출에 의해 호출되었음을 나타냅니다. JVM 옵션 -XX:+DisableExplicitGC를 사용하여 이러한 전체 GC를 비활성화할 수 있습니다.