본문으로 건너뛰기
Previous
Next
C++ Valgrind: A Practical Memory Debugging Complete Guide

C++ Valgrind: A Practical Memory Debugging Complete Guide

C++ Valgrind: A Practical Memory Debugging Complete Guide

이 글의 핵심

Learn Valgrind for C++: install Memcheck, detect leaks and invalid access, interpret output, use suppressions, and compare tools—with examples and SEO-friendly tips.

Introduction

Valgrind is a powerful toolkit for memory leaks, bugs, and profiling in C/C++ programs. On Linux and macOS it is essential for tracking down memory issues.

1. Installation and basic usage

Installation

# Ubuntu/Debian
sudo apt-get install valgrind
# macOS
brew install valgrind
# Check version
valgrind --version

Basic usage

# Compile (debug symbols)
g++ -g program.cpp -o program
# Run Valgrind
valgrind --leak-check=full ./program
# More detail
valgrind --leak-check=full --show-leak-kinds=all ./program
# Track origins of uninitialized values
valgrind --track-origins=yes ./program

2. Detecting memory leaks

Example 1: Memory leak

// leak.cpp
#include <iostream>
int main() {
    int* ptr = new int(42);
    
    std::cout << *ptr << std::endl;
    
    return 0;
}
g++ -g leak.cpp -o leak
valgrind --leak-check=full ./leak

Sample output:

==12345== HEAP SUMMARY:
==12345==     in use at exit: 4 bytes in 1 blocks
==12345==   total heap usage: 1 allocs, 0 frees, 4 bytes allocated
==12345== 
==12345== 4 bytes in 1 blocks are definitely lost
==12345==    at 0x4C2E0EF: operator new(unsigned long)
==12345==    by 0x400B2C: main (leak.cpp:5)

Example 2: Uninitialized memory

// uninit.cpp
#include <iostream>
int main() {
    int x;
    
    if (x > 0) {
        std::cout << "positive" << std::endl;
    }
    
    return 0;
}
g++ -g uninit.cpp -o uninit
valgrind --track-origins=yes ./uninit

Sample output:

==12345== Conditional jump or move depends on uninitialised value(s)
==12345==    at 0x400B2C: main (uninit.cpp:6)

Example 3: Invalid memory access

// invalid.cpp
#include <iostream>
int main() {
    int arr[10];
    
    for (int i = 0; i <= 10; ++i) {
        arr[i] = i;
    }
    
    return 0;
}
g++ -g invalid.cpp -o invalid
valgrind ./invalid

Sample output:

==12345== Invalid write of size 4
==12345==    at 0x400B2C: main (invalid.cpp:7)

3. Valgrind tools

Memcheck

valgrind --tool=memcheck ./program

Cachegrind

valgrind --tool=cachegrind ./program
cg_annotate cachegrind.out.12345

Callgrind

valgrind --tool=callgrind ./program
kcachegrind callgrind.out.12345

Helgrind

valgrind --tool=helgrind ./program

Massif

valgrind --tool=massif ./program
ms_print massif.out.12345

4. Common issues

Issue 1: Performance

# Valgrind is very slow (often 10–50×)
# Use only in development/testing
# Test with small inputs
valgrind --leak-check=full ./program < small_input.txt

Issue 2: False positives

# Generate suppression rules
valgrind --gen-suppressions=all ./program > my.supp
# Use suppressions
valgrind --suppressions=my.supp ./program

Example my.supp:

{
   <system_library_leak>
   Memcheck:Leak
   fun:malloc
   fun:system_function
}

Issue 3: Missing debug info

# ❌ No debug symbols
g++ program.cpp -o program
valgrind ./program
# ✅ Use -g
g++ -g program.cpp -o program
valgrind ./program

Issue 4: Optimization level

# ❌ Heavy optimization
g++ -O3 -g program.cpp
# ✅ Lower optimization for clearer stacks
g++ -O0 -g program.cpp

5. Interpreting output

Leak kinds

# Definite leak
definitely lost: 100 bytes in 5 blocks
# Indirect leak
indirectly lost: 50 bytes in 2 blocks
# Possible leak
possibly lost: 20 bytes in 1 blocks
# Still reachable at exit
still reachable: 30 bytes in 3 blocks

Quick reference

KindMeaningAction
definitely lostTrue leakFix
indirectly lostLeak via parent pointerFix parent leak
possibly lostPossible leakInvestigate
still reachableStill pointed to at exitOften OK; free on shutdown if strict

6. Practical examples

Example 1: Smart pointers

// smart_ptr.cpp
#include <memory>
#include <iostream>
int main() {
    auto ptr = std::make_unique<int>(42);
    
    std::cout << *ptr << std::endl;
    
    return 0;
}
g++ -g smart_ptr.cpp -o smart_ptr
valgrind --leak-check=full ./smart_ptr

Sample output:

==12345== HEAP SUMMARY:
==12345==     in use at exit: 0 bytes in 0 blocks
==12345==   total heap usage: 1 allocs, 1 frees, 4 bytes allocated
==12345== 
==12345== All heap blocks were freed -- no leaks are possible

Example 2: Vector of raw pointers

// vector_leak.cpp
#include <vector>
#include <iostream>
int main() {
    std::vector<int*> vec;
    
    for (int i = 0; i < 5; i++) {
        vec.push_back(new int(i));
    }
    
    return 0;
}
g++ -g vector_leak.cpp -o vector_leak
valgrind --leak-check=full ./vector_leak

Fix:

// vector_fixed.cpp
#include <vector>
#include <iostream>
int main() {
    std::vector<int*> vec;
    
    for (int i = 0; i < 5; i++) {
        vec.push_back(new int(i));
    }
    
    for (auto ptr : vec) {
        delete ptr;
    }
    
    return 0;
}

Summary

Key takeaways

  1. Valgrind: Memory debugging and profiling framework
  2. Memcheck: Memory error and leak detection
  3. Cachegrind: Cache profiling
  4. Helgrind: Threading errors
  5. Cost: Often 10–50× slower

Tool comparison

ToolPurposeTypical slowdown
MemcheckMemory errors10–50×
CachegrindCache analysis20–100×
CallgrindCall graphs20–100×
HelgrindThread errors20–50×
MassifHeap profiling~20×

Practical tips

  • Compile with -g
  • Use --leak-check=full
  • Test with small inputs
  • Use suppression files for known false positives
  • Prefer smart pointers

Next steps



자주 묻는 질문 (FAQ)

Q. 이 내용을 실무에서 언제 쓰나요?

A. Learn Valgrind for C++: install Memcheck, detect leaks and invalid access, interpret output, use suppressions, and compa… 실무에서는 위 본문의 예제와 선택 가이드를 참고해 적용하면 됩니다.

Q. 선행으로 읽으면 좋은 글은?

A. 각 글 하단의 이전 글 또는 관련 글 링크를 따라가면 순서대로 배울 수 있습니다. C++ 시리즈 목차에서 전체 흐름을 확인할 수 있습니다.

Q. 더 깊이 공부하려면?

A. cppreference와 해당 라이브러리 공식 문서를 참고하세요. 글 말미의 참고 자료 링크도 활용하면 좋습니다.


같이 보면 좋은 글 (내부 링크)

이 주제와 연결되는 다른 글입니다.


이 글에서 다루는 키워드 (관련 검색어)

C++, Valgrind, memory, debugging, tools 등으로 검색하시면 이 글이 도움이 됩니다.