2012-04-24 12 views
6

Kontynuacją pytanie Memory leaks when calling ITK from Visual Studio DLLVS2010 donosi fałszywe przecieki pamięci dla klas statycznych w DLL

I rafinowany problem z najprostszym przykładzie.

struct A 
    { 
    public: 
    A() 
     { 
     mp_data = new int(0x42); 
     } 
    ~A() 
     { 
     delete mp_data; 
     } 
    int* mp_data; 
    }; 

A a; 

Kiedy taka klasa globalna jest zdefiniowana w bibliotece DLL, Visual Studio debugowania CRT informuje, że mp_data wyciekają podczas zamykania aplikacji. Czy ktoś zna obejście, z wyjątkiem wyłączenia raportowania wycieków?

+0

To może być błąd Visual Studio. Zobacz komentarze pod zaakceptowaną odpowiedzią [tutaj] (http://stackoverflow.com/questions/2204608/does-c-call-destructors-for-global-andclcl-static-variables). –

+0

Nie, to nie jest powód. W debugerze zweryfikowałem, że naprawdę nazywa się '~ A()'. – Andrey

Odpowiedz

5

Jeśli wywołasz _CrtDumpMemoryLeaks() na końcu głównej funkcji, oczekiwane jest zachowanie, ponieważ mp_data zostanie usunięte po wywołaniu _CrtDumpMemoryLeaks().

Musisz wywołać _CrtDumpMemoryLeaks() po wywołaniu ostatniego destruktora statycznych obiektów (lub raczej w ostatnim destruktorze po zwolnieniu pamięci), jeśli nie chcesz widzieć tych przecieków (dość trudne zadanie, nie zrobiłbym tego Spróbuj).

Odkurzacz podejście jest przeznaczyć wszystkie swoje statycznych obiektów na stercie zamiast (na początku main) i zwalnianie ich na końcu main, a następnie można nazwać _CrtDumpMemoryLeaks() i przyzwyczajenie widać żadnych wycieków pamięci.

Obiekty statyczne FYI z konstruktorami i destruktorami są uważane za złe, ponieważ kolejność, w jakiej są konstruowane/usuwane, nie jest deterministyczna, a z tego powodu statyczne obiekty często wprowadzają błędy, które nie mogą być łatwo debugowane.

Edytuj dotyczące komentarzu Andrey za: Można spróbować wyłączyć automatyczne wywołanie _CrtDumpMemoryLeaks wywołując _CrtSetDbgFlag aby rozbroić flagę _CRTDBG_LEAK_CHECK_DF. Jeśli to działa, możesz dodać statyczny obiekt, który wywołuje _CrtDumpMemoryLeaks() w swoim destruktorze. Aby mieć pewność, że obiekt ten zostanie zniszczony jako ostatni, można użyć wartości #pragma init_seg(compiler) directive.

Nie ma pojęcia, czy to zadziała ... poza tym wszystkie inne rozwiązania najprawdopodobniej będą wymagały modyfikacji biblioteki ITK (co powinno być możliwe, w końcu jest to biblioteka typu open source ?!).

+0

To nie ma zastosowania, ponieważ (1) Nie wywołuję samej _CrtDumpMemoryLeaks(), biblioteka runtime VS robi to za mnie; (2) w rzeczywistości statyczne obiekty znajdują się w bibliotece innej firmy, która jest poza moją kontrolą (kliknij link w pytaniu) – Andrey

+0

@Andrey: zobacz moją edycję – smerlin

+0

Dziękuję, to działa! – Andrey

2

Każde z poniższych rozwiązań rozwiązuje problem.

(1) Tworzenie fałszywych zależność DLL na MFC lub

(2) Użyj rozwiązanie sugerowane przez smerlin: dodaj ten kod obok DllMain

struct _DEBUG_STATE 
    { 
    _DEBUG_STATE() {} 
    ~_DEBUG_STATE() { _CrtDumpMemoryLeaks(); } 
    }; 

#pragma init_seg(compiler) 
_DEBUG_STATE ds; 
2

uderzę ten sam objaw w trakcie migracji biblioteki wewnętrznej z łączenia statycznego z dynamicznym łączeniem czasu ładowania i okazało się, że w moim przypadku problem polegał na tym, że projekt DLL i projekt EXE były połączone z różnymi wersjami bibliotek runtime/MFC VC++ (jedna to był MBCS, a drugi to Unicode).

W moim przypadku zarówno aplikacja, jak i biblioteka używały MFC, a destruktor _AFX_DEBUG_STATE, który aktywuje zrzut wycieków pamięci CRT, był wywoływany dwa razy, dla dwóch oddzielnych obiektów - ponieważ biblioteka DLL i EXE są połączone z różnymi bibliotekami plików DLL środowiska wykonawczego, Stan statyczny w środowisku wykonawczym został skutecznie zduplikowany. Jedna z bibliotek DLL wyładuje i wyrzuci wycieki zbyt wcześnie i pokażą kilka fałszywych wycieków. Przełączenie obu projektów na ten sam zestaw znaków rozwiązało oddzielne powiązanie środowiska wykonawczego, a także rozwiązało fałszywe raporty o wyciekach.

W moim przypadku powiązanie z dwoma oddzielnymi środowiskami wykonawczymi było niezamierzone i mogło powodować inne problemy. To oczywiście nie będzie miało miejsca w przypadku korzystania z bibliotek stron trzecich z dobrze zdefiniowanym ABI, w przypadku których nie masz kontroli nad tym, do którego CRT jest podłączona biblioteka.

Nie jestem pewien, czy miałoby to zastosowanie w twoim przypadku, ale chciałem opublikować post na wypadek, gdyby był pomocny dla innych.

0

W aplikacjach MFC można wyłączyć automatyczne wycieku zrzutu pamięci poprzez wywołanie:

AfxEnableMemoryLeakDump(FALSE); 

ten jest wspierany od Visual Studio 2010. Do dokumentacji, patrz here.

0

Miałem te same problemy w Visual Studio 2015. Wypróbowałem wszystkie rozwiązania. Pierwsze rozwiązanie z zależnością od fałszywego MFC działało tylko wtedy, gdy wybierzesz opcję kompilatora /MT w swojej bibliotece DLL. Tak więc Twoja biblioteka DLL i główna aplikacja nie będą dzielić tej samej sterty. Ale często potrzebne jest /MD, np. jeśli chcesz udostępnić kontener STL lub obiekty ciągów między biblioteką Dll i główną aplikacją (granica Dll). Jeśli zostanie użyty kod /MD, aplikacja i biblioteka dll używają tej samej sterty. Więc pierwsze rozwiązanie z zależnością od fałszywego MFC nie zadziałało dla mnie.

Nie podoba mi się drugie rozwiązanie, wyłączając wykrywanie wycieków pamięci w głównej aplikacji. Jeśli nie potrzebujesz już biblioteki DLL z tym wywołaniem destruktora, musisz pamiętać o ponownym włączeniu wykrywania wycieków pamięci w aplikacji.

Znalazłem inne rozwiązanie, więc nie miałem już wycieków z fałszywej pamięci. Musisz tylko użyć opcji linkera /delayload dla biblioteki Dll! To wszystko :-). Udało mi się to również z opcją kompilatora /MD.

Here możesz przeczytać coś na temat granicy Dll (dlaczego używać /MD?). i here można przeczytać coś na temat opcji kompilatora CRT w ogóle.

Powiązane problemy