본문으로 건너뛰기
Memory Diagnostics · 2/7

heaptrack 분석 — 가벼운 heap profiler 활용

· Hawk · 4분 읽기

Valgrind Memcheck/Massif는 정확하지만 20-100배 느림 — 운영 환경에 부적합. heaptrack2-3배 느림모든 heap allocation을 콜스택과 함께 기록. KDE 프로젝트 출신이지만 어떤 Linux 프로그램에도 적용.

#설치

Terminal window
# Fedora
$ sudo dnf install heaptrack heaptrack-gui
# Ubuntu / Debian
$ sudo apt install heaptrack heaptrack-gui
# Arch
$ sudo pacman -S heaptrack
Terminal window
$ heaptrack --version
heaptrack 1.5.0

#기본 사용

Terminal window
$ heaptrack ./myprog arg1 arg2
heaptrack output will be written to "heaptrack.myprog.12345.zst"
starting application, this might take some time...
[프로그램 실행, 평소 2-3배 시간]
[종료 시]
heaptrack stats:
allocations: 123456
leaked allocations: 78
temporary allocations: 4567

종료 시 heaptrack.myprog.<pid>.zst 생성 (zstd 압축). 분석:

Terminal window
$ heaptrack_print heaptrack.myprog.12345.zst | less

또는 GUI:

Terminal window
$ heaptrack_gui heaptrack.myprog.12345.zst

#heaptrack_print 출력

MOST CALLED FUNCTIONS
1234567 calls to:
operator new(unsigned long)
in /usr/lib/libstdc++.so.6
std::__cxx11::basic_string<...>::_M_mutate
in /usr/lib/libstdc++.so.6
parse_request
at server.cpp:42
handle_connection
at server.cpp:88
MOST ALLOCATIONS (cumulative)
800000 allocations, 256.0 MB peak, 192.0 MB leaked from:
operator new(unsigned long)
in /usr/lib/libstdc++.so.6
Cache::add
at cache.cpp:23
Server::process
at server.cpp:200
MOST TEMPORARY ALLOCATIONS # alloc + free 짧은 시간 내
12345 temporary allocations from:
std::string::operator+ allocation
...
LEAKED ALLOCATIONS
Leak: 192.0 MB from 80000 allocations at:
operator new(unsigned long)
in /usr/lib/libstdc++.so.6
Cache::add
at cache.cpp:23

핵심 정보:

섹션의미
MOST CALLEDalloc 횟수 많은 콜스택 — hot path
MOST ALLOCATIONS누적 alloc 크기 — 총 부담
MOST TEMPORARYalloc + free 짧은 시간 — 최적화 대상
LEAKED종료 시 안 free된 — 진짜 누수

#GUI — heaptrack_gui

훨씬 사용성 좋음:

  • Summary — 전체 통계
  • Bottom-Up — leaf 함수부터 (콜스택 reverse)
  • Top-Down — main부터 트리
  • Caller / Callee — 함수 단위 인-아웃
  • Consumed시간별 memory 그래프 (Massif와 동등)
  • Allocations — 시간별 alloc rate
  • Temporary Allocations — 시간별 temp rate
  • Size Histogram — alloc 크기 분포 (Power-of-2 bins)
  • Flame Graph — 콜스택 시각화

특히 Consumed 탭이 Massif의 core feature를 그대로. 시간 진행에 따른 메모리 사용 곡선 + 어느 콜스택이 얼마나 차지.

#Massif vs heaptrack

Massifheaptrack
속도20-50x 느림2-3x 느림
출력text + ms_printtext + GUI
정확도Valgrind 시뮬레이션LD_PRELOAD malloc 래퍼
메모리 그래프시각시각
콜스택 정확성매우 정확좋음 (libunwind)
운영 환경부적합적합 (느림 감수)
pthread정확정확
CPU 부하매우 큼적음

heaptrack이 대체는 아니지만 일상 사용엔 더 실용적. Massif는 최후의 정밀 분석.

#attach 모드 — 실행 중 프로세스

Terminal window
$ heaptrack --pid 12345

이미 실행 중인 프로세스에 attach. ltrace처럼 ptrace 활용.

운영 서비스의 몇 분 샘플에 매우 유용. 종료 시 자동 분리 + 파일 저장.

#분석 한 예 — 누수 진단

상황: 서비스 RSS가 1시간에 100MB씩 증가.

Terminal window
$ heaptrack ./server &
SERVER_PID=$!
$ sleep 600 # 10분
$ kill -SIGINT $SERVER_PID
$ heaptrack_gui heaptrack.server.*.zst

GUI의 Consumed 탭에서 시간 진행 메모리 그래프. 우상향 라인 + 우클릭 → “Show callers”로 어디서 alloc되는지.

LEAKED 섹션에 Cache::add at cache.cpp:23 — 해당 줄을 검토하면 _store[key] = value로 무한 누적.

#—record-only 모드

라이브러리만 attach.

Terminal window
$ heaptrack --record-only ./myprog

GUI 없이 trace만 빠르게. 데이터센터에서 자동 수집 → 후처리.

#환경 변수 옵션

Terminal window
$ HEAPTRACK_DEBUG=1 heaptrack ./myprog # 디버그 출력
$ HEAPTRACK_BACKTRACES_THREADS=1 heaptrack ... # 스레드별 분리

#환경 — LD_PRELOAD 메커니즘

heaptrack은 libheaptrack_preload.so를 LD_PRELOAD해 malloc/free/realloc/calloc/free 등을 래핑. 매 호출마다:

  1. 원본 malloc 호출.
  2. libunwind로 콜스택 추출.
  3. 압축된 trace에 기록.

종료 시 trace 파일 finalize. 압축이 zstd — 매우 작음 (수 GB heap activity → 수 MB).

#정적 링크된 바이너리

LD_PRELOAD는 동적 링크에만. 정적은 불가.

Terminal window
$ heaptrack ./static_prog
ERROR: cannot attach

해법: 동적 빌드로 재컴파일, 또는 부분 동적 (-Wl,--export-dynamic + dlopen).

#valgrind 호환?

heaptrack은 valgrind 도구가 아님. valgrind 위에서 안 돌아감 (둘 다 malloc 가로채기).

#영향 분석 — heaptrack_compare

두 trace 비교 (예: 패치 전/후).

Terminal window
$ heaptrack ./prog_before
$ heaptrack ./prog_after
$ heaptrack_print heaptrack.prog_after.*.zst -d heaptrack.prog_before.*.zst
[diff 출력 — 어디서 더 많이/적게 alloc]

CI에서 메모리 회귀 자동 검출에 활용.

#자주 만나는 함정

증상원인
error: ptraceYAMA kernel.yama.ptrace_scope. 0으로
콜스택 <unknown>디버그 심볼 없음. -g 빌드 또는 별 debuginfo
출력 너무 큼짧은 시간만 측정, 또는 --filter
Could not find heaptrack_preload.soLD_LIBRARY_PATH 환경
GUI 안 보임Qt 의존성. heaptrack-gui 별도 패키지
분석 시간 너무 김파일 너무 큼. 더 짧게 측정

#Massif와의 결합 흐름

  1. heaptrack으로 일상 모니터링 (가벼움).
  2. 의심되는 영역 발견 시 valgrind massif로 정밀 분석.
  3. 누수 위치 확정되면 ASan으로 정확한 줄 (재현 가능 시).

도구 선택은 부담·정확도·재현성의 트레이드오프.

#정리

  • heaptrack = Massif보다 10-20배 빠른 heap profiler.
  • LD_PRELOAD malloc 래퍼 + libunwind 콜스택.
  • 종료 시 zstd 압축 trace.
  • GUI의 Consumed 탭이 시간별 메모리 그래프.
  • LEAKED / MOST CALLED / TEMPORARY로 세 가지 분석.
  • attach 모드로 실행 중 프로세스에.
  • 정적 바이너리엔 적용 불가.
  • valgrind와 보완 — 일상 heaptrack, 정밀 Massif.

#다음 장 예고

Ch 3 — jemalloc / tcmalloc profiling. 표준 malloc 대체 + 내장 profiler.

#관련 항목