Jak znaleźć wyciek pamięci w kodzie/projekcie C++?

Jestem programistą C++ na platformie Windows. Używam Visual Studio 2008.

Zwykle kończę w kodzie z wyciekami pamięci.

Zwykle znajduję wyciek pamięci, sprawdzając kod, ale jest to uciążliwe i nie zawsze jest dobrym podejściem.

Ponieważ nie stać mnie na płatne narzędzie do wykrywania wycieków pamięci, chciałem, żebyście zaproponowali najlepsze możliwe sposoby uniknięcia wycieków pamięci.

  1. chcę wiedzieć, jak programista może znaleźć pamięć przecieki.
  2. Czy Jest jakiś standard lub procedura, którą należy wykonać, aby upewnić się, że nie ma wycieku pamięci w programie?
Author: Alex, 2011-06-07

18 answers

Instrukcje

Things You ' ll Need

  • biegłość w C++
  • kompilator C++
  • Debugger i inne narzędzia oprogramowania śledczego

1

Zrozumieć podstawy operatora. Operator C++ " new " przydziela pamięć sterty. Operator "delete" zwalnia pamięć sterty. Dla każdego "nowego "należy użyć" delete", aby zwolnić tę samą pamięć, którą przydzielono:

char* str = new char [30]; // Allocate 30 bytes to house a string.

delete [] str; // Clear those 30 bytes and make str point nowhere.

2

Realokuj pamięć tylko wtedy, gdy masz usunięte. W poniższym kodzie str nabywa nowy adres z drugim przydziałem. Pierwszy adres jest bezpowrotnie tracony, podobnie jak 30 bajtów, na które wskazywał. Teraz są niemożliwe do uwolnienia, a Ty masz wyciek pamięci:

char* str = new char [30]; // Give str a memory address.

// delete [] str; // Remove the first comment marking in this line to correct.

str = new char [60]; /* Give str another memory address with
                                                    the first one gone forever.*/

delete [] str; // This deletes the 60 bytes, not just the first 30.

3

Uważaj na te zadania. Każda zmienna dynamiczna (przydzielona pamięć na stercie) musi być powiązana ze wskaźnikiem. Gdy zmienna dynamiczna zostanie odłączona od wskaźnika (- ów), jej usunięcie stanie się niemożliwe. Znowu to wyniki w wycieku pamięci:

char* str1 = new char [30];

char* str2 = new char [40];

strcpy(str1, "Memory leak");

str2 = str1; // Bad! Now the 40 bytes are impossible to free.

delete [] str2; // This deletes the 30 bytes.

delete [] str1; // Possible access violation. What a disaster!

4

Uważaj na lokalne wskaźniki. Wskaźnik zadeklarowany w funkcji jest alokowany na stosie, ale dynamiczna zmienna, na którą wskazuje, jest alokowana na stercie. Jeśli nie usuniesz go, będzie on trwał po wyjściu programu z funkcji:
void Leak(int x){

char* p = new char [x];

// delete [] p; // Remove the first comment marking to correct.

}

5

Zwróć uwagę na kwadratowe szelki po "usuń."Use" delete " by self to free a single object. Użyj "delete" [] z nawiasami kwadratowymi, aby uwolnić tablicę sterty. Nie. zrób coś takiego:

char* one = new char;

delete [] one; // Wrong

char* many = new char [30];

delete many; // Wrong!

6

Jeśli przeciek jeszcze pozwolił - zwykle szukam go z deleaker (sprawdź tutaj: http://deleaker.com).

Dzięki!
 203
Author: John Smith,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-16 15:13:45

Możesz użyć pewnych technik w swoim kodzie, aby wykryć wyciek pamięci. Najczęstszym i najłatwiejszym sposobem wykrycia jest zdefiniowanie makra powiedzmy, DEBUG_NEW i użycie go wraz z predefiniowanymi makrami, takimi jak __FILE__ i __LINE__, aby zlokalizować wyciek pamięci w kodzie. Te predefiniowane makra informują o pliku i liczbie linii wycieków pamięci.

DEBUG_NEW jest tylko makrem, które jest zwykle zdefiniowane jako:

#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW

Tak, że gdziekolwiek używasz new, może również śledzić plik i numer linii, które może być użyty do zlokalizowania wycieku pamięci w programie.

Oraz __FILE__, __LINE__predefiniowanymi makrami , które oceniają odpowiednio na nazwę pliku i numer linii, gdzie ich używasz!

Przeczytaj poniższy artykuł, który bardzo pięknie wyjaśnia technikę używania DEBUG_NEW z innymi ciekawymi makrami:

Wieloplatformowy Wykrywacz Wycieku Pamięci


Z Wikpedia ,

Debug_new odnosi się do techniki w C++ przeciążenie i / lub ponowne zdefiniowanie operatora nowe i operator usunąć w celu przechwycić alokację pamięci i wywołania dealokacyjne, a tym samym debugowanie a program do wykorzystania pamięci. często polega na zdefiniowaniu makra o nazwie DEBUG_NEW i sprawia, że nowe stają się coś jak Nowy (_plik_, _linia _) aby zapisać informacje o pliku / linii na przydział. Microsoft Visual C++ wykorzystuje ta technika w swoim Microsoft Zajęcia Fundacji. Są pewne sposoby przedłużania ta metoda, aby uniknąć korzystanie z redefinicji makr, a jednocześnie możliwość wyświetlenia pliku / linii informacje na niektórych platformach. Tam jest wiele nieodłącznych ograniczeń tego metoda. Dotyczy tylko C++ i nie można złapać wycieków pamięci przez C działa jak malloc. Jednak może być bardzo prosty w użyciu, a także bardzo szybko, w porównaniu z innymi kompletne rozwiązania debuggera pamięci.

 25
Author: Nawaz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:13:15

Istnieje kilka znanych technik programowania, które pomogą Ci zminimalizować ryzyko wycieków pamięci z pierwszej ręki:

  • jeśli musisz zrobić własną dynamiczną alokację pamięci, napisz new i delete zawsze parami i upewnij się, że kod alokacji / dealokacji nazywa się parami
  • unikaj dynamicznej alokacji pamięci, jeśli możesz. Na przykład, użyj vector<T> t Gdzie jest to możliwe zamiast T* t = new T[size]
  • użyj "inteligentnych wskaźników", takich jak inteligentne wskaźniki boost ( http://www.boost.org/doc/libs/1_46_1/libs/smart_ptr/smart_ptr.htm )
  • Mój ulubiony: upewnij się, że rozumiesz pojęcie własności wskaźnika i upewnij się, że wszędzie, gdzie używasz wskaźników, wiesz, który encja kodu jest właścicielem
  • dowiedz się, które konstruktory / operatory przypisania są automatycznie tworzone przez kompilator C++ i co to oznacza, jeśli masz klasę, która posiada wskaźnik (lub co to oznacza, jeśli masz klasę, która zawiera wskaźnik do obiektu, który nie posiada ).
 13
Author: Doc Brown,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-03-20 20:20:42
  1. Pobierz narzędzia debugowania dla Windows .
  2. Użyj narzędzia gflags, aby włączyć ślady stosu w trybie użytkownika.
  3. użycie UMDH aby zrobić wiele migawek pamięci programu. Zrób migawkę przed przydzieleniem pamięci i zrób drugą migawkę po punkcie, w którym uważasz, że twój program wyciekł z pamięci. Możesz dodać przerwy lub monity w programie, aby dać ci szansę na uruchomienie UMDH i zrobienie migawek.
  4. Run UMDH ponownie, Tym razem w trybie, który robi różnicę między dwoma migawkami. Następnie wygeneruje raport zawierający stosy połączeń podejrzanych wycieków pamięci.
  5. Przywróć poprzednie ustawienia gflags po zakończeniu.

UMDH da ci więcej informacji niż sterta debugowania CRT, ponieważ obserwuje alokacje pamięci w całym procesie; może nawet powiedzieć, czy komponenty innych firm przeciekają.

 7
Author: Aaron Klotz,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:19:30
 6
Author: CantGetANick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-09-27 08:31:27

Jeśli używasz gcc, dostępny jest gprof.

Chciałem wiedzieć jak programista znaleźć wyciek pamięci

Niektórzy używają narzędzi, niektórzy robią to, co ty, może również poprzez peer code review

Czy istnieje jakiś standard lub procedura, którą należy wykonać, aby upewnić się, że nie ma wycieku pamięci w programie

Dla mnie: ilekroć tworzę dynamicznie przydzielane obiekty, zawsze umieszczam kod zwalniający po, a następnie wypełniam kod pomiędzy. To byłoby w porządku, gdyby jesteś pewien, że nie będzie WYJĄTKÓW w kodzie pomiędzy. W przeciwnym razie korzystam z try-finally (nie używam często C++).

 5
Author: LeleDumbo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:15:39
  1. W visual studio istnieje wbudowany detektor wycieku pamięci o nazwie C Runtime Library. Gdy program zakończy działanie po powrocie głównej funkcji, CRT sprawdzi stertę debugowania aplikacji. jeśli na stercie debugowania są jeszcze przydzielone jakieś bloki, to mamy wyciek pamięci..

  2. To forum omawia kilka sposobów na uniknięcie wycieku pamięci w C / C++..

 5
Author: Benny Tjia,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:25:11

Przeszukaj kod pod kątem wystąpień new i upewnij się, że wszystkie występują w konstruktorze z pasującym usunięciem w destruktorze. Upewnij się, że jest to jedyna możliwa operacja rzucania w tym konstruktorze. Prostym sposobem na to jest zawinięcie wszystkich wskaźników w std::auto_ptr lub boost::scoped_ptr (w zależności od tego, czy potrzebujesz semantyki move). Dla całego przyszłego kodu upewnij się, że każdy zasób jest własnością obiektu, który oczyszcza zasób w swoim destruktorze. Jeśli potrzebujesz semantyki move następnie można uaktualnić do kompilatora, który obsługuje odniesienia wartości r (VS2010 czy wierzę) i tworzyć konstruktory ruchu. Jeśli nie chcesz tego robić, możesz użyć różnych trudnych technik obejmujących sumienne użycie swapu lub spróbować Boost.Przenieś bibliotekę.

 5
Author: Mankarse,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-12-19 02:06:16

Uruchamianie" Valgrind " może:

1) pomoc w identyfikacji wycieków pamięci - Pokaż liczbę wycieków pamięci i wskaż linie w kodzie, w których została przydzielona wyciekająca pamięć.

2) zwróć uwagę na błędne próby uwolnienia pamięci (np. niewłaściwe wywołanie "delete")

Instrukcja użycia "Valgrind"

1) Pobierz valgrind tutaj .

1) Skompiluj swój kod za pomocą flagi-g

3) In your shell run:

valgrind --leak-check=yes myprog arg1 arg2

Gdzie "myprog" to Twój skompilowany program, a" arg1"," arg2 " argumenty Twojego programu.

4) wynikiem jest lista wywołań do malloc / new, które nie miały kolejnych wywołań do free delete.

Na przykład:

==4230==    at 0x1B977DD0: malloc (vg_replace_malloc.c:136)

==4230==    by 0x804990F: main (example.c:6)

Mówi, w której linii został wywołany malloc (który nie został uwolniony).

Jak zauważyli inni, upewnij się, że dla każdego połączenia "new"/"malloc" masz kolejne połączenie "delete" / "free".

 5
Author: Gal Nachmana,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-06-06 18:45:18

W systemie Windows można użyć CRT debug heap .

Czy Jest jakiś standard lub procedura, którą należy wykonać, aby upewnić się, że nie ma wycieku pamięci w programie.

Tak, nie używaj ręcznego zarządzania pamięcią(jeśli kiedykolwiek wywołasz delete LUB delete[] Ręcznie, robisz to źle). Użyj RAII i inteligentnych wskaźników, ogranicz alokacje sterty do absolutnego minimum (Przez większość czasu wystarczą automatyczne zmienne).

 3
Author: Cat Plus Plus,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:15:04

Odpowiadając na drugą część pytania,

Czy Jest jakiś standard lub procedura, którą należy wykonać, aby upewnić się, że nie ma wycieku pamięci w programie.

Tak, jest. I to jest jedna z kluczowych różnic między C i C++.

W C++, nigdy nie należy wywoływać new lub delete w kodzie użytkownika. RAII jest bardzo powszechnie stosowaną techniką, która w zasadzie rozwiązuje problem zarządzania zasobami. Każdy zasób w programie (zasób jest wszystko, co musi zostać pozyskane, a później wydane: uchwyty plików, gniazda sieciowe, połączenia z bazami danych, ale także zwykłe alokacje pamięci, a w niektórych przypadkach pary wywołań API (BeginX ()/EndX (), LockY (), UnlockY ()), powinny być zawinięte w klasę, gdzie:

    W przeciwieństwie do innych formatów, które nie są używane w pamięci podręcznej, nie są używane w pamięci podręcznej.]}
  • Destruktor uwalnia zasób,
  • kopiowanie i przypisywanie jest albo w przeciwieństwie do tego, że nie jest to możliwe, nie jest to możliwe, ponieważ nie jest to możliwe, ponieważ nie jest to możliwe, ponieważ nie jest to możliwe.]}

Klasa ta jest następnie tworzona lokalnie, na stosie lub jako członek klasy, A Nie przez wywołanie new i przechowywanie wskaźnika.

Często nie trzeba samemu definiować tych klas. Kontenery biblioteki standardowej zachowują się również w ten sposób, że każdy obiekt przechowywany w std::vector zostaje uwolniony gdy wektor zostanie zniszczony. Więc ponownie, nie przechowuj wskaźnika w kontenerze (który wymagałby ty aby wywołać new i delete), ale raczej obiekt sam w sobie (który daje Ci zarządzanie pamięcią za darmo). Podobnie, inteligentne klasy wskaźników mogą być używane do łatwego zawijania obiektów, które muszą być przydzielone za pomocą new, i kontrolowania ich życia.

Oznacza to, że gdy obiekt wyjdzie poza zasięg, jest on automatycznie niszczony, a jego zasób zwolniony i posprzątany.

Jeśli zrobisz to konsekwentnie w całym kodzie, po prostu nie będziesz miał żadnych wycieków pamięci. Wszystko, co mogłoby zostać wycieknięte, jest powiązane z destruktorem, który zostanie wywołany, gdy kontrola opuści zakres, w którym obiekt został zadeklarowany.

 3
Author: jalf,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2011-06-07 06:32:30

Visual Leak Detector (VLD) to darmowy, solidny, otwarty system wykrywania wycieków pamięci dla Visual C++.

Po uruchomieniu programu pod debugerem Visual Studio, Visual Leak Detector wyświetli raport wycieku pamięci po zakończeniu sesji debugowania. Raport wycieku zawiera pełny stos wywołań pokazujący, w jaki sposób zostały przydzielone wszelkie wyciekające bloki pamięci. Kliknij dwukrotnie linię w stosie połączeń, aby przejść do tego pliku i linii w edytorze okno.

Jeśli masz tylko zrzuty awaryjne, możesz użyć komendy Windbg !heap -l, która wykryje nieszczelne bloki sterty. Lepiej otwórz opcję gflags: "Create user mode stack trace database" , wtedy zobaczysz stos wywołań alokacji pamięci.

 3
Author: fresky,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-09-15 10:15:10

MTuner jest darmowym wieloplatformowym narzędziem do profilowania pamięci, wykrywania wycieków i analizy obsługującym Kompilatory MSVC, GCC i Clang. Funkcje obejmują:

  • historia użycia pamięci na podstawie osi czasu i bloków pamięci na żywo
  • wydajne filtrowanie operacji pamięci na podstawie sterty, znacznika pamięci, zakresu czasu itp.
  • SDK do ręcznego oprzyrządowania z pełnym kodem źródłowym
  • obsługa ciągłej integracji poprzez użycie wiersza poleceń
  • wywołanie drzewa stosu i Drzewa nawigacja na mapie
  • O wiele więcej.

Użytkownicy mogą profilować dowolne platformy targetujące za pomocą GCC lub clang cross Kompilatory. MTuner jest wyposażony w wbudowaną obsługę platform Windows, PlayStation 4 i PlayStation 3.

 3
Author: mtosic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2016-10-25 01:51:02

Adresssanitizer (ASan) jest szybkim wykrywaczem błędów pamięci. Znajduje błędy use-after-free i {heap,stack, global} - buffer overflow w programach C / C++. Znajduje:

  • Użyj po free (dangling pointer dereference)
  • przepełnienie bufora sterty
  • przepełnienie bufora stosu
  • Globalne przepełnienie bufora
  • Użyj po powrocie
  • błędy kolejności inicjalizacji

To narzędzie jest bardzo szybkie. Średnie spowolnienie programu jest ~2x.

 1
Author: Beginner,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-02-08 19:13:21

Możesz użyć narzędzia Valgrind do wykrywania wycieków pamięci.

Również, aby znaleźć wyciek w określonej funkcji, Użyj exit(0) Na końcu funkcji, a następnie uruchom ją za pomocą Valgrind

`$` valgrind ./your_CPP_program 
 1
Author: Divyanshu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-07-21 11:36:59

Oprócz narzędzi i metod dostępnych w innych anwerach, narzędzia do analizy kodu statycznego mogą być używane do wykrywania wycieków pamięci (i innych problemów). Darmowym narzędziem jest Cppcheck. Ale dostępnych jest wiele innych narzędzi. Wikipedia posiada listę narzędzi do analizy kodu statycznego.

 0
Author: orbitcowboy,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-05 19:10:59

To może pomóc komuś, kto po prostu chce użyć Visual Studio do wykrywania wycieków. "Narzędzia diagnostyczne" statki z wersjami VS 2015 i nowszymi są teraz znacznie ulepszone. Wypróbowałem również narzędzie o nazwie "Deleaker", ale narzędzie Visual studio jest równie dobre. Oglądanie poniższego filmu pomogło mi go rozpocząć.

Https://www.youtube.com/watch?v=HUZW8m_3XvE

 0
Author: Patel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-07-14 22:16:19

Ani "Nowy", ani" Usuń " nie powinny być nigdy używane w kodzie aplikacji. Zamiast tego utwórz nowy typ, który używa idiomu manager/worker, w którym Klasa manager przydziela i zwalnia pamięć oraz przekazuje wszystkie inne operacje obiektowi worker.

Niestety jest to więcej pracy niż powinno być, ponieważ C++ nie ma przeciążenia " operatora .". Jest to jeszcze bardziej praca w obecności polimorfizmu.

Ale to jest warte wysiłku, ponieważ wtedy nie musisz się martwić o wyciekach pamięci, co oznacza, że nawet nie musisz ich szukać.

 0
Author: s. heller,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-02-20 14:35:23