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 |