GC 로그 분석을 통한 성능 최적화
GC(Garbage Collection) 로그는 애플리케이션의 메모리 사용 패턴과 GC 성능을 이해하는 데 중요한 정보를 제공합니다. 로그 분석을 통해 GC 수집 주기, 중단 시간, 메모리 사용량 등을 파악하여 성능을 최적화할 수 있습니다. 이번 글에서는 GC 로그를 분석하는 방법과 이를 바탕으로 최적화하는 방법을 설명합니다.
GC 로그 수집
GC 로그는 .NET 애플리케이션 실행 중 GC가 어떻게 동작했는지에 대한 상세한 정보를 제공합니다. .NET에서 GC 로그를 활성화하려면 환경 변수를 설정해야 합니다.
.NET GC 로그 활성화
다음 환경 변수를 설정하여 GC 로그를 활성화할 수 있습니다.
export DOTNET_GCLog=1
export DOTNET_GCLogFile=gc-log.txt
또는 애플리케이션 실행 시 직접 옵션을 추가할 수도 있습니다.
dotnet run --gcLog gc-log.txt
이 설정을 통해 애플리케이션 실행 중에 GC 이벤트가 기록된 로그 파일이 생성됩니다.
GC 로그 분석
로그가 수집된 후에는 로그 파일을 분석하여 성능 문제를 진단할 수 있습니다. GC 로그에는 메모리 할당량, 각 세대별 GC 발생 횟수, 중단 시간 등이 기록됩니다. 이를 통해 GC 성능을 저하시키는 요소를 파악할 수 있습니다.
로그에서 확인할 주요 정보
- GC 수집 횟수: 각 세대(Gen 0, Gen 1, Gen 2)에서의 GC 수집 횟수를 확인할 수 있습니다. Gen 0 수집이 지나치게 자주 발생하면 메모리 할당 패턴을 최적화할 필요가 있습니다.
- 중단 시간(Pause Time): GC 실행으로 인해 애플리케이션이 일시 중단되는 시간을 확인할 수 있습니다. 중단 시간이 길다면 성능에 부정적인 영향을 미칠 수 있습니다.
- 메모리 사용량: GC 실행 전후의 힙 크기, Gen 0/1/2 할당량을 분석하여 메모리 관리 상태를 파악할 수 있습니다.
로그 예시
다음은 GC 로그 파일의 일부 예시입니다.
[GC Start] Generation: 0, Heap Size: 100MB
[GC End] Generation: 0, Heap Size: 60MB, Pause Time: 150ms
[GC Start] Generation: 2, Heap Size: 300MB
[GC End] Generation: 2, Heap Size: 200MB, Pause Time: 300ms
이 예시에서는 Gen 0 수집 후 힙 크기가 100MB에서 60MB로 줄었으며, 중단 시간은 150ms였습니다. 또한 Gen 2 수집 후 힙 크기가 300MB에서 200MB로 줄었으며, 이 경우 중단 시간이 300ms로 나타났습니다.
GC 로그를 통한 성능 최적화
로그에서 얻은 정보를 바탕으로 성능을 최적화할 수 있습니다. 다음은 GC 로그 분석 후 적용할 수 있는 주요 최적화 전략입니다.
중단 시간 최적화
GC 중단 시간이 길다면 Low-Latency 모드를 활용하여 중단 시간을 줄일 수 있습니다. 특히 실시간 응답이 중요한 애플리케이션에서는 이 모드를 사용하여 성능 저하를 방지할 수 있습니다.
GCSettings.LatencyMode = GCLatencyMode.LowLatency;
메모리 할당 패턴 개선
로그에서 Gen 0 수집이 자주 발생하는 경우, 메모리 할당 패턴을 최적화하여 GC 수집 빈도를 줄일 수 있습니다. 객체 풀링(Object Pooling)을 사용하면 빈번한 메모리 할당을 줄일 수 있으며, 이를 통해 Gen 0 수집을 감소시킬 수 있습니다.
public class ObjectPool<T> where T : new()
{
private readonly Stack<T> _pool = new Stack<T>();
public T GetObject()
{
return _pool.Count > 0 ? _pool.Pop() : new T();
}
public void ReturnObject(T obj)
{
_pool.Push(obj);
}
}
Large Object Heap 관리
대형 객체가 빈번하게 할당되는 경우, Large Object Heap(LOH)에서 파편화가 발생할 수 있습니다. 이 경우 LOH 압축을 통해 메모리 파편화를 줄이고 성능을 향상시킬 수 있습니다.
GCSettings.LargeObjectHeapCompactionMode = GCLargeObjectHeapCompactionMode.CompactOnce;
GC.Collect();
이 코드는 한 번의 GC 실행 시 LOH를 압축하여 메모리 파편화를 줄입니다.
GC 모드 선택
애플리케이션에 맞는 적절한 GC 모드를 선택하는 것도 중요합니다. 서버 GC는 멀티코어 시스템에서 병렬로 GC 작업을 수행하며, 워크스테이션 GC는 데스크톱 환경에서 적합한 GC 모드입니다. 적절한 모드를 선택함으로써 애플리케이션 성능을 향상시킬 수 있습니다.
export DOTNET_GCServer=1 # 서버 GC 활성화
결론
GC 로그는 애플리케이션의 메모리 사용 패턴과 GC 성능을 깊이 있게 분석하는 데 중요한 정보를 제공합니다. GC 수집 횟수, 중단 시간, 메모리 사용량 등을 바탕으로 성능 문제를 파악하고, 이를 해결하기 위한 최적화 전략을 적용할 수 있습니다. Low-Latency 모드, 객체 풀링, LOH 압축 등의 기법을 통해 GC 성능을 최적화하고, 애플리케이션의 전체 성능을 향상시킬 수 있습니다.