본문으로 건너뛰기

[Grafana Loki] pkg/dataobj를 위한 실험적 arena 스타일 메모리 패키지 도입

PR 링크: grafana/loki#20422 상태: Merged | 변경: +1043 / -0

들어가며

Grafana Loki의 pkg/dataobj에서 대량의 메모리 할당과 해제가 반복되면 GC 압력이 증가합니다. 이 PR은 arena 스타일의 메모리 Allocator를 새로 도입하여, 할당된 메모리 영역을 GC 없이 회수(Reclaim)하고 재사용할 수 있게 합니다. 64바이트 캐시라인 정렬, 비트맵 기반 free-list 관리, LSB 순서 비트맵이 포함됩니다.

핵심 코드 분석

Allocator: arena 스타일 메모리 관리

type Allocator struct {
    regions []*Memory
    free    bitmap  // 1=사용 가능, 0=사용 중
    empty   bitmap  // 1=nil(trimmed), 0=not-nil
}

func (alloc *Allocator) Allocate(size int) *Memory {
    // 1. free-list에서 적합한 영역 탐색
    for i := range alloc.free.IterValues(len(alloc.regions), true) {
        region := alloc.regions[i]
        if region != nil && cap(region.data) >= size {
            alloc.free.Set(i, false)
            return region
        }
    }
    // 2. 없으면 64바이트 정렬된 새 영역 생성
    region := &Memory{data: allocBytes(size)}
    alloc.addRegion(region, false)
    return region
}

64바이트 캐시라인 정렬 할당

func allocBytes(size int) []byte {
    const alignmentPadding = 64
    buf := make([]byte, size+alignmentPadding)
    addr := uint64(uintptr(unsafe.Pointer(&buf[0])))
    alignedAddr := memalign.Align64(addr)
    if alignedAddr != addr {
        offset := int(alignedAddr - addr)
        return buf[offset : offset+size : offset+size]
    }
    return buf[:size:size]
}

비트맵: LSB 순서의 비트팩 부울 시퀀스

type bitmap []uint64

func (set bitmap) IterValues(maxIndex int, value bool) iter.Seq[int] {
    return func(yield func(int) bool) {
        for _, word := range set {
            rem := word
            if !value {
                rem = ^rem  // 비트 반전으로 unset 비트 탐색
            }
            for rem != 0 {
                firstSet := bits.TrailingZeros64(rem)
                // ...
            }
        }
    }
}

왜 이게 좋은가

  • GC 압력 감소: Reclaim으로 영역을 "사용 가능"으로 표시하면 Go GC가 수집할 필요 없이 재사용됩니다. Trim은 미사용 영역만 GC에 반환합니다.
  • 캐시라인 정렬: 64바이트 정렬로 CPU 캐시 효율을 높입니다.
  • Apache Arrow 호환: LSB 비트 순서는 Apache Arrow의 validity 버퍼와 boolean 배열 표현과 호환됩니다.
  • 계층적 Allocator: 부모 Allocator에서 자식을 생성하여 메모리 풀을 계층적으로 관리할 수 있습니다.
  • 포괄적 테스트: Allocator의 Reclaim/Trim 동작과 비트맵 연산에 대한 테스트가 포함됩니다.

참고 자료

댓글

관련 포스트

PR Analysis 의 다른글