Menu
Szybki wybór
Hosting Domeny VPS SSL Kalkulator Porównania FAQ
Aktywne kody
Wszystkie kody rabatowe

Valgrind — wykrywanie wycieków pamięci i błędów w aplikacjach

Opublikowano: 10 kwietnia 2026 · Kategoria: VPS

Serwer restartuje się co kilka dni przez OOM Killer. Aplikacja C++ działa poprawnie przez godziny, po czym nagle pada z segfault. Natywne rozszerzenie PHP wycieka pamięć pod obciążeniem. To są typowe scenariusze, gdzie Valgrind jest nieocenionym narzędziem — dynamicznie analizuje każdą operację na pamięci i wskazuje dokładnie gdzie i dlaczego coś się dzieje źle, z pełnym stack trace. Bez konieczności modyfikacji kodu źródłowego.

Instalacja i Memcheck — podstawowe użycie

# Ubuntu/Debian
sudo apt install valgrind kcachegrind massif-visualizer -y

# Podstawowe uruchomienie (Memcheck — domyślne narzędzie)
valgrind ./myapp

# Pełne opcje dla maksymalnej detekcji błędów
valgrind \
  --leak-check=full \
  --show-leak-kinds=all \
  --track-origins=yes \
  --verbose \
  --log-file=valgrind-report.txt \
  ./myapp arg1 arg2

# Wyjaśnienie flag:
# --leak-check=full      — pokazuj każdy blok wycieku osobno
# --show-leak-kinds=all  — wszystkie kategorie (def/indir/poss/reach)
# --track-origins=yes    — śledź skąd pochodzi niezainicjalizowana wartość
# --log-file=            — zapis do pliku (raport może być duży)
# --error-exitcode=1     — return 1 gdy są błędy (dobre dla CI)

# PHP z Memcheck (test rozszerzeń natywnych)
valgrind --leak-check=full \
  /usr/bin/php -c /etc/php/8.2/cli/php.ini \
  -d extension=myext.so \
  test.php

Interpretacja raportu Memcheck

==12345== HEAP SUMMARY:
==12345==     in use at exit: 4,096 bytes in 1 blocks
==12345==   total heap usage: 150 allocs, 149 frees, 45,678 bytes allocated
==12345==
==12345== 4,096 bytes in 1 blocks are definitely lost in loss record 1 of 1
==12345==    at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck.so)
==12345==    by 0x10921F: create_buffer (myapp.c:42)
==12345==    by 0x109345: process_request (myapp.c:87)
==12345==    by 0x1094A2: main (myapp.c:124)
==12345==
==12345== LEAK SUMMARY:
==12345==    definitely lost: 4,096 bytes in 1 blocks   <-- PROBLEM
==12345==    indirectly lost: 0 bytes in 0 blocks
==12345==      possibly lost: 256 bytes in 2 blocks
==12345==    still reachable: 2,048 bytes in 5 blocks   <-- zazwyczaj OK
==12345==         suppressed: 0 bytes in 0 blocks
==12345==
==12345== ERROR SUMMARY: 1 errors from 1 contexts (suppressed: 0 from 0)

# Kategorie LEAK SUMMARY:
# definitely lost  — wskaźnik całkowicie utracony. MUSISZ naprawić.
# indirectly lost  — przez inne "definitely lost". Naprawa tamtych = fix tu.
# possibly lost    — Valgrind nie jest pewny. Może być celowe.
# still reachable  — program zakończył się nie zwalniając. Często OK (globals).
# suppressed       — wyciszony przez plik .supp (znane false positives bibliotek)

Suppression files — eliminacja false positives

Biblioteki systemowe (OpenSSL, glibc, Python runtime) często wykazują "wycieki" które są celowe lub nieistotne. Pliki suppressions pozwalają wyciszyć znane false positives.

# Generuj plik suppressions na podstawie bieżącego raportu
valgrind --leak-check=full --gen-suppressions=all ./myapp 2>all-suppressions.txt

# Edytuj i zachowaj interesujące suppressions
# Przykład pliku myapp.supp:
# {
#   openssl_init_suppression
#   Memcheck:Leak
#   match-leak-kinds: reachable
#   fun:malloc
#   fun:CRYPTO_malloc
#   fun:sk_reserve
#   obj:*libssl.so*
# }

# Użyj pliku suppressions
valgrind --suppressions=myapp.supp --leak-check=full ./myapp

# Gotowe pliki supp dla popularnych bibliotek:
# /usr/lib/valgrind/default.supp (domyślnie załadowany)
# Dla Pythona: valgrind --suppressions=${PREFIX}/lib/python*/test/valgrind-python.supp python3 test.py

Callgrind — profilowanie cache i funkcji

# Uruchom z narzędziem Callgrind
valgrind --tool=callgrind ./myapp
# Wynik: callgrind.out.12345 (numer PID)

# Opcje szczegółowe
valgrind \
  --tool=callgrind \
  --callgrind-out-file=myapp.callgrind \
  --cache-sim=yes \
  --branch-sim=yes \
  --instr-atstart=no \  # nie zbieraj od startu (użyj CALLGRIND_START_INSTRUMENTATION w kodzie)
  ./myapp

# Szybki tekstowy raport
callgrind_annotate callgrind.out.12345 | head -80

# Wizualizacja w KCachegrind (GUI)
kcachegrind callgrind.out.12345 &

# KCachegrind pokazuje:
# - Flat Profile: ile instrukcji/cykli kosztuje każda funkcja
# - Call Graph: drzewo wywołań z kosztami
# - Source Annotation: linia po linii z kosztami
# - Cache simulation: L1/L2/LL miss rates per function

Massif — profilowanie sterty (heap profiler)

Massif śledzi użycie pamięci sterty w czasie — pozwala zobaczyć kiedy i dlaczego aplikacja alokuje coraz więcej pamięci. Niezbędny gdy aplikacja nie wycieka (Memcheck czysto) ale ciągle rośnie.

# Uruchom Massif
valgrind --tool=massif ./myapp
# Wynik: massif.out.12345

# Tekstowy raport (ms_print)
ms_print massif.out.12345 | head -100

# Output pokazuje "snapshots" użycia pamięci:
# --------------------------------------------------------------------------------
#    n        time(i)         total(B)   useful-heap(B) extra-heap(B)    stacks(B)
# --------------------------------------------------------------------------------
#    0              0                0               0             0            0
#   10      1,234,567        2,345,678       2,300,000        45,678            0
#   20      2,345,678        4,567,890       4,500,000        67,890            0
# [peak snapshot pokazuje najwyższy punkt użycia pamięci]

# Szczegóły szczytu użycia (kto alokował)
ms_print massif.out.12345 | grep -A 30 "peak"

# GUI: massif-visualizer (Ubuntu)
massif-visualizer massif.out.12345 &

# Profilowanie stosu (stack) oprócz sterty
valgrind --tool=massif --stacks=yes ./myapp

Porównanie Valgrind z AddressSanitizer i innymi narzędziami

Narzędzie Narzut Rekompilacja Wykrywa Najlepsze do
Valgrind Memcheck 10-50x wolniej Nie (działa na binarce) Wycieki, invalid reads, UAF, uninitialized Binaries bez źródeł, skomplikowane wycieki
AddressSanitizer (ASan) 2-3x wolniej Tak (-fsanitize=address) Buffer overflow, UAF, double-free Dev z kompilacją, szybkie wykrywanie
LeakSanitizer (LSan) 2x wolniej Tak (-fsanitize=leak) Tylko wycieki pamięci Szybka detekcja wycieków w CI
MemorySanitizer (MSan) 3-5x wolniej Tak (-fsanitize=memory) Uninitialized reads (tylko) Wykrywanie niezainicjalizowanych wartości
Valgrind Callgrind 10-50x wolniej Nie Cache misses, call graph, hot functions Cache analysis, call graph visualization
heaptrack 3-5x wolniej Nie (LD_PRELOAD) Heap allocations, wycieki Nowoczesna alternatywa dla Massif

Najczęstsze pytania

Co to jest Valgrind i jakie błędy wykrywa? +
Valgrind to framework do dynamicznej analizy programów, składający się z wielu narzędzi. Memcheck (domyślny) wykrywa: memory leaks (wyciek pamięci — brak free/delete), invalid reads i writes (dostęp poza zakresem bufora), use-after-free (dostęp do zwolnionej pamięci), double-free (dwukrotne zwolnienie), uninitialized values (użycie niezainicjalizowanej pamięci). Jest niezastąpiony przy debugowaniu programów C/C++ oraz natywnych rozszerzeń Python, Ruby, PHP i Node.js.
Czym różni się Valgrind od AddressSanitizer? +
Valgrind działa bez rekompilacji — uruchamia program na wirtualnej maszynie (narzut 10-50x, średnio 20x). AddressSanitizer (ASan) to flaga kompilatora (-fsanitize=address) — wymaga rekompilacji ale ma znacznie mniejszy narzut (2-3x). ASan jest szybszy i wykrywa błędy w locie, Valgrind jest dokładniejszy w analizie wycieków. Wybór: Valgrind gdy nie masz źródeł lub dla bibliotek, ASan gdy kompilujesz sam i potrzebujesz szybszej analizy.
Co to jest Callgrind i jak go używać? +
Callgrind to narzędzie profilowania cache i wywołań funkcji wchodzące w skład Valgrind. Symuluje CPU i zlicza instrukcje, dostępy do cache L1/L2/LLC dla każdej funkcji. Uruchomienie: valgrind --tool=callgrind ./myapp, wyniki w callgrind.out.PID. Do wizualizacji użyj KCachegrind (Linux) lub QCachegrind (macOS/Windows) — pokazuje call graph, hot paths i cache miss rates per function.
Jak czytać raport Valgrind Memcheck? +
Raport Valgrind kończy się podsumowaniem LEAK SUMMARY z kategoriami: "definitely lost" (wyciek — wskaźnik utracony, pamięć nieosiągalna), "indirectly lost" (wyciek przez referencję od directly lost), "possibly lost" (wskaźnik wewnętrzny, może być celowy), "still reachable" (pamięć dostępna w momencie zakończenia — często bufor globalny, nie zawsze błąd). Priorytet naprawy: definitely lost > indirectly lost > possibly lost. Still reachable można zazwyczaj ignorować.

Sprawdź oferty pasujące do tego scenariusza

Poniżej masz szybkie przejścia do ofert i stron z kodami rabatowymi tam, gdzie są dostępne.