Golang GC
작성일: / 수정일:
Golang GC (가비지 컬렉터) 주요 내용
Golang GC : GOGC
- 유효하지 않는 메모리(Dangling Object)를 주기적으로 해제하는 기법
- Java의
Parallel GC
,G1GC
와 유사하나 구현 방식에서 차이가 있음 - Stop-the-World 시간을 최소화하도록 설계됨
- Java의
- Tri-Color Algorithm 사용
- 동시성을 고려한 효율적인 메모리 관리 알고리즘
- CMS (Concurrent Mark and Sweep) 방식 운영
- Java 와 같은 Generation GC 기법이나 Compaction은 지원하지 않음
- 대신 더 효율적인 메모리 할당 전략을 사용
- Compaction (압축, 재배치) 가 없음
- 재배치를 하지 않는 대신
TCMalloc
를 통한 메모리 할당 관리 - 메모리 단편화를 최소화하고 빠른 할당을 지원
- 멀티쓰레드 최적화 힙 메모리 할당기 - tcmalloc. jemalloc
- 재배치를 하지 않는 대신
Tri-Color Algorithm 동작 원리
white
, black
, grey
세 가지 상태를 통한 메모리 관리
- 초기 단계
- 모든 메모리 객체를
white
상태로 설정 - 이는 잠재적으로 수집 가능한 상태를 의미
- 모든 메모리 객체를
- 마킹 단계
GC Root
에서 직접 참조하는 객체들을grey
로 표시grey
객체들은 검사가 필요한 상태를 의미
- 스캐닝 단계
grey
상태 객체가 참조하는 다른 객체들을grey
로 표시- 검사가 완료된 객체는
black
으로 변경 - 이 과정을 grey 객체가 없을 때까지 반복
- 수집 단계
- 남아있는
white
상태의 객체들을 메모리에서 해제 - 이 객체들은 더 이상 접근할 수 없는(unreachable) 상태
- 남아있는
TCMalloc (Thread-Caching Malloc)
- Google이 개발한 고성능 메모리 할당기
- 특징:
- Thread 별 캐시를 통한 빠른 메모리 할당
- 크기별로 최적화된 할당 전략 사용
- 메모리 단편화 최소화
- Lock contention 감소로 인한 성능 향상
- 장점:
- 멀티스레드 환경에서 우수한 성능
- 메모리 재사용 최적화
- 캐시 지역성 향상
- 할당/해제 오버헤드 감소
GOGC 옵션
가비지 컬렉션 대상 백분율 설정
이전 수집 후 남은 라이브 데이터에 대한 새로 할당된 데이터의 비율을 조정
GOGC=100
: 기본값, 100% 비율- 힙이 라이브 메모리의 100%만큼 증가하면 GC 트리거
GOGC=50
: GC를 더 자주 실행- 메모리 사용량은 줄지만 CPU 사용량 증가
GOGC=200
: GC를 덜 자주 실행- CPU 사용량은 줄지만 메모리 사용량 증가
GOGC=off
: GC를 사용하지 않음- 특수한 경우에만 사용 (벤치마크, 테스트 등)
GC Trace 활용
gctrace
옵션을 통한 가비지 컬렉션 모니터링
예제 코드
package main
import (
"fmt"
"sync"
"time"
)
type log struct {
Info string
Seq int
}
func main() {
wg := sync.WaitGroup{}
for i := 0; i < 1000000; i++ {
wg.Add(1)
go func() {
defer wg.Done()
info := fmt.Sprintf("test %d", i)
_ = log{info, i}
// fmt.Println(s, t)
time.Sleep(time.Millisecond * 1000)
}()
}
wg.Wait()
}
실행 및 모니터링
# 프로젝트 초기화
$ go mod init gctest
$ go mod tidy
# build
$ go build
실행 테스트
# GODEBUG=gctrace=1 : gctrace 활성화
$ GODEBUG=gctrace=1 ./gctest
트레이스 출력 분석
gc 1 @0.010s 9%: 0.058+2.6+0.083 ms clock, 0.46+6.6/2.9/0+0.66 ms cpu, 4->5->4 MB, 5 MB goal, 8 P
gc 2 @0.015s 19%: 0.093+4.7+0.17 ms clock, 0.74+14/6.1/0+1.4 ms cpu, 6->7->6 MB, 8 MB goal, 8 P
gc 3 @0.027s 25%: 0.15+5.7+0.34 ms clock, 1.2+22/9.0/0+2.7 ms cpu, 10->13->11 MB, 13 MB goal, 8 P
gc 4 @0.044s 29%: 0.084+11+0.35 ms clock, 0.67+45/18/0+2.8 ms cpu, 18->22->20 MB, 23 MB goal, 8 P
gc 5 @0.076s 31%: 0.24+17+0.19 ms clock, 1.9+66/31/0+1.5 ms cpu, 32->37->34 MB, 40 MB goal, 8 P
gc 6 @0.129s 33%: 0.13+26+0.065 ms clock, 1.1+124/50/4.6+0.52 ms cpu, 54->62->58 MB, 68 MB goal, 8 P
gc 7 @0.214s 34%: 0.095+40+0.099 ms clock, 0.76+204/79/0.34+0.79 ms cpu, 93->98->91 MB, 116 MB goal, 8 P
gc 8 @0.355s 35%: 0.086+66+0.12 ms clock, 0.69+375/132/0+0.99 ms cpu, 152->158->144 MB, 182 MB goal, 8 P
gc 9 @0.605s 35%: 0.11+109+0.087 ms clock, 0.88+624/216/0+0.70 ms cpu, 252->261->242 MB, 289 MB goal, 8 P
gc 10 @1.033s 35%: 0.077+206+1.0 ms clock, 0.61+1021/397/0.93+8.1 ms cpu, 430->437->403 MB, 484 MB goal, 8 P
출력 항목 설명:
gc 1
: GC 실행 번호@0.010s
: 프로그램 시작 후 경과 시간9%
: GC에 사용된 CPU 시간 비율0.058+2.6+0.083 ms
: 각 GC 단계별 소요 시간4->5->4 MB
: GC 전후의 힙 크기 변화5 MB goal
: 목표 힙 크기8 P
: 사용된 프로세서 수
댓글남기기