Debugowanie pamięci w systemie Linux: kluczowe narzędzia i techniki

Ostatnia aktualizacja: 26 z lutego 2026
  • Linux oferuje polecenia, takie jak free, vmstat, ps i top, które umożliwiają sprawdzenie faktycznego wykorzystania pamięci i procesora, rozróżniając pamięć używaną, wolną i buforowaną.
  • Narzędzia takie jak GDB i Valgrind umożliwiają wykrywanie błędów segmentacji, wycieków pamięci, nielegalnego dostępu i niezainicjowanych zmiennych w programach natywnych.
  • W środowiskach .NET Core połączenie dotnet-dump, LLDB i SOS ułatwia szczegółową analizę zrzutów pamięci zarówno w systemie Linux, jak i Windows.
  • Uporządkowany obieg prac diagnostycznych, który łączy metryki systemowe, logi i analizę zrzutów, znacznie skraca czas lokalizowania i rozwiązywania problemów z pamięcią.

Debugowanie pamięci w systemie Linux

Gdy coś idzie nie tak na serwerze Linux, przyczyną często jest sposób wykorzystania pamięci i narzędzia debugowania . Dopóki jednak nie wiesz, na co zwracać uwagę, wszystko wydaje się chaotycznym zbiorem liczb i procesów. Zrozumienie, co dzieje się w pamięci RAM, jak zachowują się Twoje programy i jak zapisywać zrzuty pamięci, jest kluczem do uniknięcia ślepego rozwiązywania problemów za każdym razem, gdy pojawia się dziwny błąd lub błąd segmentacji.

W tym artykule szczegółowo i w przystępny sposób omówimy, jak sprawdzać pamięć, debugować programy i analizować zrzuty w systemie Linux za pomocą poleceń systemowych (free, vmstat, /proc/meminfo), debugerów takich jak GDB, analizatorów pamięci takich jak Valgrind oraz narzędzi specyficznych dla .NET i innych środowisk. Celem jest, abyś po tym artykule dysponował praktycznym arsenałem narzędzi do diagnozowania problemów z pamięcią i procesorem w serwerach i profesjonalnych środowiskach programistycznych.

Przegląd: Pamięć w systemie Linux i dlaczego nie należy przejmować się 100%

Na serwerze Linux pamięć RAM działa jak szybki magazyn danych i kodu, które system będzie wkrótce ponownie wykorzystywać. Dostęp do pamięci RAM jest znacznie szybszy niż do dysku, dlatego jądro wykorzystuje to, aby wykorzystać ją jako pamięć podręczną dla plików, buforów i stron pamięci, które mogą być wkrótce ponownie potrzebne.

W kontekście serwera WWW z systemem Apache lub Nginx albo serwera bazy danych, takiego jak MySQL lub MariaDB, wiedza o tym, ile pamięci jest używane, ile jest wolne, a ile jest buforowane, jest kluczowa dla prawidłowego doboru rozmiaru usług oraz zrozumienia przestrzeni nazw i grup c . W rzeczywistości narzędzia optymalizacyjne, takie jak MySQLTuner , wykorzystują te dane (i inne informacje) do sugerowania ustawień bufora, pamięci podręcznej i połączenia.

Ważne jest, aby zrozumieć koncepcję, która często na początku zaskakuje: pamięć RAM jest zaprojektowana do użytku . 90%, a nawet 100% wykorzystania niekoniecznie stanowi problem; Linux wypełnia pamięć RAM dyskową pamięcią podręczną, aby przyspieszyć działanie systemu. Prawdziwy niepokój pojawia się, gdy pojawiają się błędy braku pamięci , procesy zawieszają się z komunikatem OOM (Out Of Memory) lub usługi zawieszają się, a nie tylko wtedy, gdy wykres pokazuje „wysokie wykorzystanie”.

Przejście do agresywnej optymalizacji ma sens tylko wtedy, gdy zauważysz, że serwer staje się niestabilny, powolny lub zatrzymuje usługi z powodu nadmiernego wykorzystania pamięci, lub gdy wiesz, że zbliżają się skoki ruchu, które mogą przytłoczyć obecne zasoby.

Podstawowe polecenia do sprawdzania pamięci w systemie Linux

Narzędzia pamięci w systemie Linux

Pierwszym krokiem w rozwiązywaniu problemów z pamięcią jest zrozumienie całkowitej ilości pamięci RAM i jej podziału na pamięć używaną, wolną, pamięć podręczną i pamięć wymiany. Linux oferuje kilka narzędzi do tego celu, każde o innym poziomie szczegółowości.

polecenie free: szybki przegląd pamięci RAM i swapu

Najczęściej używanym poleceniem do szybkiego podglądu jest za darmo, szczególnie z parametrem -h Aby wyświetlić rozmiary w czytelnym formacie: Aby uzyskać więcej informacji na temat interpretacji i optymalizacji tych metryk, zobacz optymalizacja statystyk pamięci.

free -h

Typowy wynik pokazuje w kilku wierszach całkowitą, używaną, wolną, współdzieloną, buforową i podręczną pamięć RAM i przestrzeń wymiany. Zobaczysz coś takiego:

Łączna liczba wykorzystanych wolnych buforów współdzielonych w pamięci podręcznej Pamięć: 2.0 G 1.5 G 470 M 300 M 0 B 414 M -/+ bufory/pamięć podręczna: 1.1 G 885 M Wymiana: 0 B 0 B 0 B

Linia -/+ buffers/cache Jest to szczególnie przydatne, ponieważ pokazuje pamięć faktycznie wykorzystywaną przez procesy (z wyłączeniem buforów/pamięci podręcznej) oraz pamięć potencjalnie dostępną dla nowych aplikacji. Wiele osób widzi niewiele „wolnej pamięci” w pierwszym wierszu i wpada w panikę, podczas gdy w rzeczywistości znaczna jej część jest po prostu buforowana i może być… ponownie wykorzystane bez dramatów.

vmstat: aktywna, bezczynna pamięć i metryki systemowe

Jeśli potrzebujesz czegoś bardziej szczegółowego, vmstat zapewnia bardziej techniczny obraz systemu. Dzięki:

vmstat -s -S M

Otrzymasz listę zawierającą całkowitą ilość pamięci, pamięć używaną, pamięć wolną, pamięć aktywną, pamięć nieaktywną, bufory, pamięć wymiany itd. Na przykład:

2048 M pamięci całkowitej 1582 M pamięci użytej 1124 M pamięci aktywnej 406 M pamięci nieaktywnej 465 M pamięci wolnej 0 M pamięci buforowej 407 M pamięci podręcznej wymiany 0 M całkowitej wymiany 0 M używanej wymiany 0 M wolnej wymiany

Koncepcja pamięci bezczynnej jest interesująca: to pamięć, która jest uznawana za używaną, ale nie jest powiązana z aktywnymi procesami, więc w praktyce zachowuje się jak pamięć, którą system może odzyskać . To pomaga wyjaśnić, dlaczego Linux może sprawiać wrażenie, że „zajmuje całe miejsce”, ale w rzeczywistości ma miejsce do zwolnienia w razie potrzeby.

/proc/meminfo: surowe szczegóły jądra

Jeśli interesują Cię wszystkie szczegóły obsługiwane przez jądro, możesz zawsze zajrzeć do pliku /proc/meminfo :

cat /proc/meminfo

Plik ten zawiera dziesiątki pól związanych z zarządzaniem pamięcią wewnętrzną : całkowita pamięć, wolna pamięć, bufory, pamięć podręczna, bloki, hugepages, dostępna pamięć itd. Jest on bardzo przydatny dla narzędzi automatycznych i skryptów monitorujących, chociaż jego bezpośrednie odczytanie jest nieco mniej przyjazne dla użytkownika niż „free” lub „vmstat” i wymaga dokładnego zrozumienia znaczenia każdego pola.

Panele sterowania i ich „równoległa rzeczywistość”

Jeśli zarządzasz serwerem za pomocą paneli sterowania, takich jak cPanel, Plesk, VestaCP lub Webmin , zauważysz, że zazwyczaj wyświetlają one wykresy wykorzystanej, wolnej i buforowanej pamięci za pośrednictwem interfejsu webowego. Dane te są wygodne, ale należy pamiętać, że są one okresowo aktualizowane i czasami nie odzwierciedlają dokładnego stanu w czasie rzeczywistym. Do dokładnej diagnostyki i precyzyjnego dostrajania zawsze najlepiej jest użyć terminala i jego natywnych poleceń.

Debugowanie procesów i pamięci za pomocą narzędzi systemowych

Gdy już wiesz, ile pamięci jest dostępne i jak jest ona ogólnie wykorzystywana, kolejnym krokiem jest zlokalizowanie procesów, które nieprawidłowo zużywają zasoby , i przeanalizowanie ich zachowania. W tym miejscu do gry wchodzą klasyczne narzędzia, takie jak ps, top, htop, strace i ltrace, a także polecenia sieciowe i dyskowe, które pomagają wyeliminować wąskie gardła.

ps, top i htop: prześwietlenie procesów i procesora

Polecenie `ps` wyświetla aktywne procesy. W połączeniu z filtrami i sortowaniem pozwala szybko zlokalizować procesy obciążające procesor.

ps aux --sort=-%cpu | head

Pokazuje procesy posortowane według procentowego wykorzystania procesora , pamięci, użytkownika i polecenia. Idealnie nadaje się jako migawka do identyfikacji głównego podejrzanego, gdy serwerowi brakuje zasobów; znajomość terminala pozwala na szybkie działanie.

  Grace Hopper: Pionierka programowania komputerowego

Z drugiej strony, `top` i jego bardziej wizualna odmiana `htop` oferują podgląd procesów w czasie rzeczywistym, użycia procesora, użycia pamięci, stanu (R, S, D itd.) oraz średniego obciążenia . `top` zaczyna się od:

top -o %CPU

Możesz skupić się na tym, które procesy najbardziej obciążają procesor. Poza liczbami, ważne jest, aby szukać wzorców :

  • Procesy w stanie R (uruchomione) które pozostają na górze przez długi czas.
  • Nagłe zmiany średniego obciążenia które wskazują na ostatnie szczyty obciążenia.
  • Przydział procesora w %us, %sy i %wa (czas użytkownika, czas systemowy i oczekiwanie na wejście/wyjście).
  • Jeśli problematyczny proces to usługa systemowa, konkretny użytkownik lub demon.
  • Jeżeli konsumpcja jest stabilna lub Porusza się skokowo w górę i w dół., co może wskazywać na zadania wsadowe lub nieregularny ruch.

Bardzo wysoka wartość %wa (oczekiwanie na wejście/wyjście) może być wskazówką, że wąskie gardło może nie znajdować się w procesorze, lecz w dysku lub podsystemie pamięci masowej.

Przeglądanie wątków w procesie: góra -H

W przypadku aplikacji wielowątkowych (Java, Python, Node itp.) nie wystarczy wiedzieć, który proces zużywa procesor; trzeba zobaczyć, który konkretny wątek wymyka się spod kontroli . W przypadku:

top -H -p PID

Otrzymujesz szczegółowe informacje o każdym wątku w procesie. Jeśli jeden z nich wyświetla się jako 100%, a pozostałe są bezczynne, prawdopodobnie występuje nieskończona pętla, dziwny problem z blokowaniem lub źle zaprojektowana sekcja krytyczna w tej części kodu.

Priorytet procesu: nice i renice

Jeśli proces intensywnie wykorzystujący zasoby jest uzasadniony, ale chcesz zapobiec jego przeciążeniu reszty systemu, możesz dostosować jego priorytet (tzw. niceness) . Polecenia `nice` i `renice` pozwalają uruchamiać procesy z niższym priorytetem lub dostosować priorytet istniejącego procesu, dzięki czemu jądro przydziela im mniej czasu procesora w porównaniu z innymi krytycznymi zadaniami.

Inne kluczowe polecenia: pidof, kill, strace i ltrace

Kiedy system jest pod presją, przydatna jest możliwość szybkiej lokalizacji i kontroli procesów:

  • pidof:pobiera PID procesu na podstawie jego nazwy, idealne rozwiązanie w przypadku skryptów lub szybkich interwencji.
  • zabić: wysyła sygnały do ​​procesów (TERM, KILL itp.), aby zostały wyłączone w sposób uporządkowany lub aby przerwały pracę, jeśli utknęły.
  • strace:pokazuje wywołania systemowe który wykonuje proces; idealny do sprawdzenia, na czym się opiera (odczyty z dysku, gniazda itp.).
  • śladPodobny do strace, ale skupiony na telefony do księgarni, przydatne do debugowania problemów związanych z korzystaniem ze współdzielonego interfejsu API.

Narzędzia te są przydatne nie tylko do wykrywania wycieków pamięci lub awarii, ale są również szeroko stosowane w cyberbezpieczeństwie, analizie kryminalistycznej i debugowaniu dziwnego zachowania plików binarnych .

Polecenia dla plików i dysków: lsof, df, du, locate

Gdy podejrzewasz, że coś jest nie tak z pamięcią masową (np. wiele otwartych plików lub pełne dyski), do gry wchodzą inne polecenia:

  • lsof:wymień pliki otwarte przez proces, przydatne do znajdowania wycieków deskryptorów lub plików, które uniemożliwiają odmontowanie systemu plików.
  • df:pokazuje wolne miejsce na dysku według systemu plików, niezbędne jest wykluczenie 100% dysków powodujących kaskadowe awarie.
  • du:obliczyć przestrzeń używana przez katalogi, bardzo przydatne do lokalizowania folderów, które rozrastają się w sposób niekontrolowany (logi, kopie zapasowe itp.).
  • zlokalizować: umożliwia wyszukiwanie plików według nazwy przy użyciu indeksowanej bazy danych, co w wielu sytuacjach jest szybsze niż polecenie find.

Polecenia sieciowe do diagnostyki: nc, netstat, ab, tcpdump, wireshark, nmap

Często problemom z wydajnością i pamięcią towarzyszą wąskie gardła sieciowe lub ataki , dlatego warto mieć pod ręką kilka podstawowych narzędzi:

  • nc (netcat):prawdziwy scyzoryk szwajcarski w dziedzinie sieci; otwiera gniazda, wysyła i odbiera dane, pozwala na testowanie usług, a nawet tworzenie improwizowanych tuneli.
  • netstat: wyświetla aktywne połączenia, gniazda nasłuchujące i statystyki sieciowe. Przydatne, gdy chcemy sprawdzić, czy do danego portu nawiązano dużo połączeń.
  • ab (test porównawczy Apache):generuje obciążenie serwera WWW w celu zmierzenia czasu reakcji i zachowania pod obciążeniem.
  • tcpdump i Wireshark: przechwytywanie pakietów sieciowych do dogłębnie analizuj ruch; tcpdump w konsoli, Wireshark z graficznym interfejsem.
  • nmapSkaner portów i usług, powszechnie stosowany zarówno do audytów bezpieczeństwa, jak i sprawdzania powierzchnia ekspozycji serwera.

GDB: klasyczny debugger błędów pamięci i awarii środowiska wykonawczego

Gdy program w systemie Linux ulega awarii z powodu błędu segmentacji lub innego poważnego błędu, kolejnym logicznym krokiem jest użycie dobrego debugera. W świecie GNU sztandarowym narzędziem jest GDB (GNU Debugger) , który pozwala na sprawdzenie stanu wewnętrznego programu, zatrzymanie go w dowolnym momencie, sprawdzenie zmiennych i zużycia pamięci oraz śledzenie wykonywania krok po kroku.

GDB został pierwotnie zaprojektowany dla programów w językach C i C++, ale został rozszerzony na inne języki, takie jak Rust, a nawet assembler , oraz na obsługę ścieżek bibliotecznych, takich jak LD_LIBRARY_PATH . Jest on fundamentalny w programowaniu, ale także w cyberbezpieczeństwie, gdzie jest wykorzystywany do inżynierii wstecznej, wyszukiwania luk w zabezpieczeniach oraz tworzenia i debugowania exploitów.

Uruchom GDB i uruchom program

Aby użyć GDB z plikiem wykonywalnym, zaleca się skompilowanie programu za pomocą informacje debugowania korzystając z opcji -g z GCC:

gcc -g -Wall programa.c -o programa

Następnie uruchamiasz go za pomocą:

gdb programa

W GDB program nie jest jeszcze uruchomiony. Możesz go uruchomić za pomocą:

  • biegaćUruchom program z dowolnymi argumentami.
  • początek: to samo co run, ale zatrzymuje się na początku funkcji main.

Jeśli masz plik wykonywalny o nazwie np. SUMA A jeśli chcesz zobaczyć, jak przetwarza swoje argumenty, przejdź do GDB i użyj run 3 5 aby uruchomić go z tymi parametrami z debugera.

Punkty przerwania i punkty obserwacyjne: wstrzymywanie programu w razie potrzeby

Punkty przerwania to punkty zatrzymania w kodzie źródłowym: gdy wykonywanie do nich dotrze, program zatrzymuje się, umożliwiając sprawdzenie jego stanu wewnętrznego. W GDB definiuje się je za pomocą polecenia :

break lugar

gdzie „lokalizacja” może być nazwą funkcji, numerem wiersza lub plikiem:wierszem . Typowy przykład:

break main

Dzięki temu GDB zatrzymuje się dokładnie w momencie wejścia do funkcji głównej. Gdy program zatrzyma się w punkcie przerwania, możesz wyświetlić kod za pomocą l (lista), sprawdzić zmienne i poruszać się po stosie wywołań.

Punkty obserwacyjne działają inaczej: zamiast zatrzymywać się w określonym miejscu kodu, zatrzymują się, gdy zmienia się wartość zmiennej . Są bardzo przydatne do wykrywania uszkodzeń pamięci lub nieoczekiwanych modyfikacji struktur krytycznych bez konieczności wypełniania kodu poleceniami print.

Precyzyjna kontrola przepływu: krok, dalej, kontynuuj, zakończ

Po zatrzymaniu programu w punkcie przerwania możesz postępować na kilka sposobów:

  • krok: wykonuje następujący wiersz i wprowadza wywoływane funkcje.
  • Następny: wykonuje następujący wiersz bez wprowadzania funkcji (uruchamia je „wszystkie naraz”).
  • kontynuować: wznawia wykonywanie do następnego punktu przerwania lub do zakończenia programu.
  • koniec: kontynuuje działanie do momentu powrotu bieżącej funkcji i powrotu do punktu, z którego została wywołana.
  Python zorientowany obiektowo: Wprowadzenie dla początkujących

Pozwala to na inspekcję podejrzanego kodu krok po kroku, bez konieczności „połykania” całego programu. Przydatna sztuczka: w GDB, Naciśnięcie Enter powtarza ostatnie polecenieidealny do robienia wielu next o step a potem mniej pisania.

Stos wywołań i ramki: zobacz, jak do tego doszliśmy

Aby zrozumieć, dlaczego w danym momencie wystąpiła awaria, kluczowe jest sprawdzenie, które funkcje zostały wywołane przed tym momentem. Struktura przechowująca te informacje to stos wywołań . GDB oferuje kilka poleceń do zarządzania nim:

  • bt (backtrace): pokazuje kompletny stos z listą zagnieżdżonych funkcji i numerami ramek.
  • up:przesuwa się o jeden poziom wyżej w stosie, do punktu, w którym wywołano bieżącą funkcję.
  • na dół: schodzi o jeden poziom niżej, do funkcji, która była uruchomiona.
  • fr (ramka): wyświetla aktualną ramkę lub umożliwia zmianę na inną poprzez wskazanie jej numeru.

Dzięki temu możesz umiejscowić się na różnych poziomach wywołania (na przykład przechodząc z funkcji wewnętrznej do main ) i zobaczyć, jak zmienne znajdowały się w każdym miejscu.

Interakcja z pamięcią: set, return, backtrace yx

Jedną z największych zalet GDB jest możliwość odczytu i modyfikacji pamięci podczas zatrzymania programu. Oto kilka przydatnych operacji:

  • zestaw: zmienia wartość zmiennej w trakcie wykonywania, idealne do testowania scenariuszy bez konieczności ponownej kompilacji.
  • wartość zwracana: zmusza bieżącą funkcję do zwrócenia określonej wartości, bez dalszego wykonywania jej kodu.
  • ślad wstecz:już widziane, aby pokazać bieżący stos wywołań.
  • x: bada zawartość pamięci zaczynając od adresu, przy użyciu różnych formatów i rozmiarów (na przykład, x/4xw 0x7fffffffe000 (aby zobaczyć cztery słowa w systemie szesnastkowym).

Za pomocą tych opcji można replikować błędy, sprawdzać, czy niebezpieczne dane wejściowe powodują przepełnienie, lub badać złożone struktury danych na stosie lub stercie.

Debugowanie post mortem z użyciem zrzutów pamięci

Linux może wygenerować plik core , gdy proces ulega awarii z powodu sygnału takiego jak SIGSEGV. Plik ten zawiera pełny stan procesu w momencie awarii: pamięć, rejestry, stos itp. Aby go aktywować w sesji, wystarczy:

ulimit -c unlimited

Aby włączyć je na stałe dla użytkowników, możesz edytować plik /etc/security/limits.conf i dodać wiersz taki jak ten:

* soft core unlimited

Gdy program ulega awarii, generuje plik, zazwyczaj o nazwie „core”, w katalogu roboczym. Można go następnie przeanalizować za pomocą GDB w następujący sposób:

gdb ejecutable core

Umożliwia to przeprowadzenie analizy post mortem, niemal tak jakby program wciąż działał. Jest to idealne rozwiązanie, gdy awarii nie da się łatwo odtworzyć na żądanie.

Valgrind: polowanie na wycieki pamięci i błędy

W przypadku wielu problemów z pamięcią w C/C++ (i podobnych językach), GDB nie wystarcza, ponieważ nie jest zaprojektowane do automatycznego wykrywania nielegalnych odczytów, wycieków ani niezainicjowanego użycia pamięci . Tu właśnie pojawia się Valgrind – system debugowania i profilowania, który emuluje procesor i monitoruje każdy dostęp do pamięci.

Valgrind zawiera kilka narzędzi, ale najczęściej używanym jest Memcheck , który zastępuje standardowego menedżera pamięci języka C własnym, zawierającym strefy ochronne wokół przydzielonych bloków . Pozwala to na wykrywanie:

  • Niezainicjowane użycie pamięci (zmienne używane przed przypisaniem im wartości).
  • Czytania/pisma po wykonaniu zajęć wolnych (używać po zwolnieniu).
  • Dostęp poza granicami bloku pamięci.
  • Wycieki pamięci (malloc bez wolnych, utraconych wskaźników, itp.).

Przykład bezbłędny: „czysty” program w Memcheck

Załóżmy, że kompilujesz krótki program „hello world” z informacjami debugowania:

gcc -Wall -gstabs valgrind_hello_good.c -o valgrind_hello_good

Jeśli uruchomisz go pod Valgrindem, używając:

valgrind --tool=memcheck --leak-check=full -v ./valgrind_hello_good

Otrzymasz ślad, w którym na końcu PODSUMOWANIE BŁĘDÓW wskazuje 0 błędów i brak wycieków. To potwierdza, że ​​przynajmniej z punktu widzenia Memchecka, program nie wykazuje anomalii pamięci.

Wykrywanie wycieków pamięci

Jeśli zmodyfikujesz kod, aby wykonać operację malloc bez zwalniania pamięci (na przykład rezerwując bajt i nigdy go nie zwalniając), a następnie przekompilujesz:

gcc -Wall -gstabs valgrind_hello_bad.c -o valgrind_hello_bad

podczas biegania:

valgrind --tool=memcheck --leak-check=full -v ./valgrind_hello_bad

Valgrind wyświetli PODSUMOWANIE STUDENTA z wartością różną od zera „in use at exit”, wskazującą ilość niewykorzystanej pamięci. Dodatkowo sekcja „definitywnie utracona” pokaże liczbę wyciekniętych bajtów i bloków, wraz ze śladem wywołań, które spowodowały wyciek (funkcja, plik i wiersz kodu).

W przypadku bardziej złożonych przypadków, w których stosuje się np. filtry, 100 bajtów w funkcji leak()Wyjście z Valgrind wyraźnie wskaże Ci drogę malloc problematyczne, pozwalające na dodanie free odpowiadające i sprawdź później, czy podsumowanie powróci do zerowego poziomu wycieków.

Nielegalne czyny i dostęp poza zasięgiem

Innym typowym błędem wykrywanym przez Memcheck jest zapis pod nieprawidłowe adresy , na przykład zapis do komórki pamięci 0 (NULL) lub poza koniec tablicy. Jeśli skompilujesz program, który wykonuje niedozwolony zapis:

gcc -gstabs -Wall valgrind_illegal_read_write.c -o valgrind_illegal_read_write

i uruchamiasz go z:

valgrind -v ./valgrind_illegal_read_write

Zobaczysz wiadomości takie jak:

Nieprawidłowy zapis rozmiaru 4 w 0x80483C4: main (valgrind_illegal_read_write.c:8) Adres 0x0 nie jest umieszczony w stosie, nie jest przydzielony do specjalnej lokalizacji ani (ostatnio) nie został zwolniony

Dzięki temu dowiesz się dokładnie, gdzie wystąpił nielegalny zapis i jak duży był tekst, co w normalnych warunkach zwykle objawia się jako prosty „błąd segmentacji” bez żadnych dalszych wskazówek.

Niezainicjowane zmienne i zależności między nimi

Memcheck powiadamia Cię również, gdy Decyzja sterująca zależy od niezainicjowanej zmiennejJeśli kompilujesz program ze zmienną lokalną, która nigdy nie jest inicjowana i jest używana w if:

gcc -gstabs -Wall valgrind_unitialized.c -o valgrind_unitialized

i uruchamiasz to za pomocą:

valgrind -v --track-origins=yes ./valgrind_unitialized

Wynik będzie zawierał coś takiego:

Warunkowy skok lub ruch zależy od niezainicjowanych wartości w 0x80483F2: main (valgrind_unitialized.c:9) Niezainicjowana wartość została utworzona przez alokację stosu w 0x80483EA: main (valgrind_unitialized.c:7)

Parametr –track-origins=yes pomaga zlokalizować miejsce, w którym niezainicjowana zmienna została utworzona po raz pierwszy, co znacznie przyspiesza poprawianie kodu.

Nadużywanie wolnych zasobów i wykrywanie błędów w stercie

Valgrind weryfikuje również, że free jest wywoływane tylko w przypadku prawidłowych wskaźnikówJeśli spróbujesz zwolnić pamięć, która nie pochodzi z mallocAlbo klikając dwukrotnie na ten sam blok otrzymasz komunikaty takie jak ten:

Nieprawidłowe free() / delete / delete[] / realloc() w 0x402B06C: free (...) przez 0x8048449: main (valgrind_illegal_free.c:11)

W wielu przypadkach informuje Cię nawet o adresie, z którego dzwonisz free Znajduje się bezpośrednio za blokiem, który został już zwolniony, co umożliwia identyfikację błędy w obliczeniach wskaźników lub podwójne zwolnienia.

  Kompletny przewodnik: Czym jest Axios JS, jak działa i dlaczego go potrzebujesz?

Podsumowując, Valgrind to narzędzie niezbędne w przypadku podejrzenia wycieków pamięci, użycia pamięci po zwolnieniu lub uszkodzenia pamięci w programach natywnych, a jego połączenie z GDB zapewnia bardzo szczegółowy obraz stanu wewnętrznego aplikacji.

Zrzuty pamięci i analiza w systemach Linux i Windows

W nowoczesnych aplikacjach, zwłaszcza w środowisku .NET Core , analiza złożonych problemów z pamięcią lub wydajnością często wiąże się z przechwytywaniem zrzutów pamięci w celu przeprowadzenia dokładnej analizy na innym komputerze. Zrzuty te zamrażają stan procesu w określonym momencie, podobnie jak tradycyjny zrzut pamięci.

Analiza zrzutów .NET w systemie Linux za pomocą dotnet-dump i LLDB

W środowiskach .NET Core w systemie Linux jednym z zalecanych narzędzi jest dotnet-dump . Po przechwyceniu zrzutu można rozpocząć analizę za pomocą:

dotnet-dump analyze <dump-file>

Ważne jest, aby analizę przeprowadzić na maszynie o tej samej architekturze i dystrybucji Linuksa , co środowisko, w którym wygenerowano zrzut. dotnet-dump jest ukierunkowany na zarządzany kod .NET. Aby analizować również kod natywny (C/C++), bardziej odpowiednie jest użycie LLDB wraz z rozszerzeniem SOS.

LLDB umożliwia debugowanie zarówno kodu zarządzanego, jak i natywnego, a za pomocą dotnet-sos można zainstalować rozszerzenie SOS, które udostępnia specyficzne polecenia dla platformy .NET. Aby poprawnie załadować zrzut .NET Core, LLDB i SOS wymagają określonych plików binarnych ze środowiska, w którym zrzut został utworzony:

  1. libmscordaccore.so
  2. libcoreclr.so
  3. DotNet (host użyty do uruchomienia aplikacji)

Te pliki binarne można zazwyczaj pobrać za pomocą narzędzia dotnet-symbol . Jeśli jest to kompilacja prywatna lub nie znajdują się one na serwerze symboli, zawsze można je skopiować z oryginalnego komputera. Jeśli pliki binarne nie są dołączone do pliku zrzutu, można użyć następującego polecenia w LLDB/SOS:

  • setclrpath <ruta> aby wskazać lokalizację plików binarnych .NET Core.
  • setsymbolserver -directory <ruta> aby określić lokalizację symboli.

Gdy już masz wszystko, czego potrzebujesz, załaduj zrzut do LLDB, określając host dotnet jako plik wykonywalny do debugowania:

lldb --core <dump-file> <host-program>

Tutaj To droga do wysypiska i Zwykle jest binarny. dotnet, chyba że jest to aplikacja niezależna. W takim przypadku będzie to osobny plik wykonywalny aplikacji (bez rozszerzenia .dll).

W ramach bazy danych LLDB często zachodzi konieczność skonfigurowania prawidłowego serwera symboli setsymbolserver -ms aby skorzystać z serwera Microsoft lub setsymbolserver -directory <ruta> dla katalogu lokalnego i uruchom loadsymbols aby załadować symbole natywne. Stamtąd możesz użyć standardowych poleceń SOS do analizy zarządzanego stosu, wątków, wyjątków itp.

Analiza zrzutu Linuksa z systemu Windows

Zrzuty generowane w systemie Linux nie ograniczają się do analizy w tym samym systemie; można je również otwierać w systemie Windows za pomocą narzędzi takich jak Visual Studio, WinDbg czy dotnet-dump. Możliwości są różne:

  • visual Studio:umożliwia czyszczenie wysypisk śmieci mieszanką kod natywny i zarządzanyz bardzo przyjaznym dla użytkownika interfejsem graficznym. Zaleca się zapoznanie się z konkretnym przewodnikiem. Debugowanie zrzutów pamięci programu Visual Studio.
  • WinDbgZaawansowane wsparcie dla zrzutów użytkowników, w tym Zrzuty Linuksa Z przepływem pracy podobnym do systemu Windows. Do zrzutów z systemów Linux x64 lub Arm64 należy używać wersji x64 WinDbg, a do zrzutów x86 wersji x86.
  • dotnet-dump W systemie Windows: używa się go w ten sam sposób, co w systemie Linux, z dotnet-dump analyzePamiętaj, aby wybrać wersję x64 lub x86 narzędzia w zależności od architektury zrzutu.

Profesjonalna diagnoza wysokiego wykorzystania procesora i pamięci

Poza konkretnymi narzędziami, czyszczenie pamięci w Linuksie zazwyczaj wymaga ustrukturyzowanego procesu , aby uniknąć przypadkowych działań. Praktyczny schemat dla serwerów wygląda następująco:

  • Patrzeć na Top w celu wykrywania podejrzanych wzorców i procesów ładowania.
  • Potwierdź za pomocą ps procesy wykorzystujące najwięcej procesora i pamięci.
  • Sprawdź, czy zużycie jest logiczne (kompilacja, wsad, indeksowanie), czy też przypomina nietypowe zachowanie.
  • Analizuj wątki za pomocą góra -H -p PID jeśli chodzi o procesy wielowątkowe.
  • Sprawdzić dzienniki serwisowe z journalctl lub tail.
  • Sprawdź, czy problem rzeczywiście jest związany z procesorem, czy też jest ukryty w... wejście/wyjście dysku używając iostat.

Aby ustalić, czy wąskie gardło występuje w procesorze czy na dysku, bardzo pomocne jest polecenie iostat -xz 1 3 : jeśli widzisz dyski o wysokim obciążeniu i długim czasie oczekiwania, a także wysokim %wa w top , problem prawdopodobnie nie leży w procesorze, lecz w pamięci masowej.

Dzięki zastosowaniu tego przepływu pracy łatwiej jest diagnozować takie przypadki, jak:

  • Boty lub złośliwy ruch wyzwalanie procesów php-fpm i przeciążanie serwera WWW.
  • Un Mikrousługa Java z wątkiem w pętli nieskończonej pochłaniając cały rdzeń.
  • Proces Pythona, który wydaje się być ograniczony przez procesor, ale w rzeczywistości jest zablokowany, czekam na dysk w każdej iteracji pętli.

Łącząc narzędzia systemowe (ps, top, vmstat, free), debugery (GDB, LLDB, dotnet-dump), analizatory pamięci (Valgrind) oraz polecenia sieciowe i dyskowe, można stworzyć sposób pracy, w którym problemy z pamięcią i wydajnością w systemie Linux przestaną być czarną skrzynką , a staną się czymś, co przy odrobinie metody i cierpliwości można zidentyfikować i naprawić z dużą dokładnością.

zaawansowany monitor systemu dla systemu Linux
Podobne artykuły:
Zaawansowany monitor systemu Linux: kompletny przewodnik