heaptrack 분석 — 가벼운 heap profiler 활용
Valgrind Memcheck/Massif는 정확하지만 20-100배 느림 — 운영 환경에 부적합. heaptrack은 2-3배 느림에 모든 heap allocation을 콜스택과 함께 기록. KDE 프로젝트 출신이지만 어떤 Linux 프로그램에도 적용.
#설치
# Fedora$ sudo dnf install heaptrack heaptrack-gui
# Ubuntu / Debian$ sudo apt install heaptrack heaptrack-gui
# Arch$ sudo pacman -S heaptrack$ heaptrack --versionheaptrack 1.5.0#기본 사용
$ heaptrack ./myprog arg1 arg2heaptrack 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 압축). 분석:
$ heaptrack_print heaptrack.myprog.12345.zst | less또는 GUI:
$ heaptrack_gui heaptrack.myprog.12345.zst#heaptrack_print 출력
MOST CALLED FUNCTIONS1234567 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 ALLOCATIONSLeak: 192.0 MB from 80000 allocations at: operator new(unsigned long) in /usr/lib/libstdc++.so.6 Cache::add at cache.cpp:23핵심 정보:
| 섹션 | 의미 |
|---|---|
| MOST CALLED | alloc 횟수 많은 콜스택 — hot path |
| MOST ALLOCATIONS | 누적 alloc 크기 — 총 부담 |
| MOST TEMPORARY | alloc + 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
| Massif | heaptrack | |
|---|---|---|
| 속도 | 20-50x 느림 | 2-3x 느림 |
| 출력 | text + ms_print | text + GUI |
| 정확도 | Valgrind 시뮬레이션 | LD_PRELOAD malloc 래퍼 |
| 메모리 그래프 | 시각 | 시각 |
| 콜스택 정확성 | 매우 정확 | 좋음 (libunwind) |
| 운영 환경 | 부적합 | 적합 (느림 감수) |
| pthread | 정확 | 정확 |
| CPU 부하 | 매우 큼 | 적음 |
heaptrack이 대체는 아니지만 일상 사용엔 더 실용적. Massif는 최후의 정밀 분석.
#attach 모드 — 실행 중 프로세스
$ heaptrack --pid 12345이미 실행 중인 프로세스에 attach. ltrace처럼 ptrace 활용.
운영 서비스의 몇 분 샘플에 매우 유용. 종료 시 자동 분리 + 파일 저장.
#분석 한 예 — 누수 진단
상황: 서비스 RSS가 1시간에 100MB씩 증가.
$ heaptrack ./server &SERVER_PID=$!$ sleep 600 # 10분$ kill -SIGINT $SERVER_PID$ heaptrack_gui heaptrack.server.*.zstGUI의 Consumed 탭에서 시간 진행 메모리 그래프. 우상향 라인 + 우클릭 → “Show callers”로 어디서 alloc되는지.
LEAKED 섹션에 Cache::add at cache.cpp:23 — 해당 줄을 검토하면 _store[key] = value로 무한 누적.
#—record-only 모드
라이브러리만 attach.
$ heaptrack --record-only ./myprogGUI 없이 trace만 빠르게. 데이터센터에서 자동 수집 → 후처리.
#환경 변수 옵션
$ HEAPTRACK_DEBUG=1 heaptrack ./myprog # 디버그 출력$ HEAPTRACK_BACKTRACES_THREADS=1 heaptrack ... # 스레드별 분리#환경 — LD_PRELOAD 메커니즘
heaptrack은 libheaptrack_preload.so를 LD_PRELOAD해 malloc/free/realloc/calloc/free 등을 래핑. 매 호출마다:
- 원본 malloc 호출.
- libunwind로 콜스택 추출.
- 압축된 trace에 기록.
종료 시 trace 파일 finalize. 압축이 zstd — 매우 작음 (수 GB heap activity → 수 MB).
#정적 링크된 바이너리
LD_PRELOAD는 동적 링크에만. 정적은 불가.
$ heaptrack ./static_progERROR: cannot attach해법: 동적 빌드로 재컴파일, 또는 부분 동적 (-Wl,--export-dynamic + dlopen).
#valgrind 호환?
heaptrack은 valgrind 도구가 아님. valgrind 위에서 안 돌아감 (둘 다 malloc 가로채기).
#영향 분석 — heaptrack_compare
두 trace 비교 (예: 패치 전/후).
$ heaptrack ./prog_before$ heaptrack ./prog_after$ heaptrack_print heaptrack.prog_after.*.zst -d heaptrack.prog_before.*.zst[diff 출력 — 어디서 더 많이/적게 alloc]CI에서 메모리 회귀 자동 검출에 활용.
#자주 만나는 함정
| 증상 | 원인 |
|---|---|
error: ptrace | YAMA kernel.yama.ptrace_scope. 0으로 |
콜스택 <unknown> | 디버그 심볼 없음. -g 빌드 또는 별 debuginfo |
| 출력 너무 큼 | 짧은 시간만 측정, 또는 --filter |
Could not find heaptrack_preload.so | LD_LIBRARY_PATH 환경 |
| GUI 안 보임 | Qt 의존성. heaptrack-gui 별도 패키지 |
| 분석 시간 너무 김 | 파일 너무 큼. 더 짧게 측정 |
#Massif와의 결합 흐름
- heaptrack으로 일상 모니터링 (가벼움).
- 의심되는 영역 발견 시 valgrind massif로 정밀 분석.
- 누수 위치 확정되면 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.
#관련 항목
Memory Diagnostics · 2 of 7
- 1리눅스 메모리 회계 — RSS·VSS·PSS·smaps 해석
- 2heaptrack 분석 — 가벼운 heap profiler 활용
- 3jemalloc·tcmalloc Profiling — 운영 allocator의 진단 기능
- 4glibc 메모리 도구 — mtrace·mcheck·MALLOC_CHECK_
- 5운영 메모리 누수 진단 — long-running 프로세스의 진단 전략
- 6CXL 메모리 진단 — RAS·Poison List·Media Error 추적
- 7Tiered Memory 진단 — DAMON·DAMOS·Promotion/Demotion 디버깅
관련 글
운영 메모리 누수 진단 — long-running 프로세스의 진단 전략
장기 실행 서비스의 누수 추적. /proc 모니터링, cgroup memory.max, OOM 회피.
glibc 메모리 도구 — mtrace·mcheck·MALLOC_CHECK_
별 라이브러리 없이 glibc 만으로 메모리 디버깅. mtrace, mcheck, MALLOC_CHECK_.
jemalloc·tcmalloc Profiling — 운영 allocator의 진단 기능
표준 glibc malloc 대체 + 내장 profiler. pprof로 시각화.