Udostępnij za pośrednictwem


Techniki testowania MFC

Jeśli debugowania programu MFC, może być przydatne tych metod debugowania.

W tym temacie:

AfxDebugBreak

makra śledzenia

wykrywania przecieków pamięci w MFC

  • Śledzenie alokacji pamięci

  • Włączanie Diagnostyka pamięci

  • Otwieranie migawki pamięci

  • Przeglądanie statystyki pamięci

  • Dokonuje zrzutu obiektu pobierania

    • Interpretacja pamięci dokonuje zrzutu

    • Dokonuje zrzutu Dostosowywanie obiektu

    Zmniejszyć rozmiar Kompilacja debugowania MFC

    • Tworzenie aplikacji MFC z informacje debugowania dla wybranych modułów

AfxDebugBreak

MFC zapewnia specjalny interfejs AfxDebugBreak funkcję w celu przerwania zakodowane na stałe w kodzie źródłowym:

AfxDebugBreak( );

Na platformach Intel AfxDebugBreak tworzy następujące kodu, które przerwy w źródle kodu zamiast kodu jądra:

_asm int 3

W innych platform AfxDebugBreak jedynie wywołuje DebugBreak.

Należy usunąć AfxDebugBreak instrukcji podczas tworzenia wersji tworzenia lub użyj #ifdef _DEBUG otaczającego je.

W tym temacie

Makra śledzenia

Aby wyświetlić komunikaty z programu debugera okno dane wyjściowe, można użyć ATLTRACE makra lub MFC śledzenia makra.Podobnie jak potwierdzeń, makra śledzenia są aktywne tylko wtedy, gdy wersja debugowania programu i zniknąć po skompilowany w wersji.

Poniższe przykłady pokazują niektóre sposoby używania śledzenia makra.Podobnie jak printf, śledzenia makra może obsłużyć liczba argumentów.

int x = 1;
int y = 16;
float z = 32.0;
TRACE( "This is a TRACE statement\n" );

TRACE( "The value of x is %d\n", x );

TRACE( "x = %d and y = %d\n", x, y );

TRACE( "x = %d and y = %x and z = %f\n", x, y, z );

Makra śledzenia prawidłowo obsługuje zarówno char * i wchar_t * parametrów.Poniższe przykłady pokazują, użyj makra śledzenia, łącznie z różnych typów parametrów ciągu.

TRACE( "This is a test of the TRACE macro that uses an ANSI string: %s %d\n", "The number is:", 2);

TRACE( L"This is a test of the TRACE macro that uses a UNICODE string: %s %d\n", L"The number is:", 2);

TRACE( _T("This is a test of the TRACE macro that uses a TCHAR string: %s %d\n"), _T("The number is:"), 2);

Aby uzyskać więcej informacji na temat śledzenia makra, zobacz Usługi diagnostyczne.

W tym temacie

Wykrywanie pamięci przeciek w MFC

MFC zawiera klasy i funkcji wykrywania pamięci, który jest przydzielony, ale nigdy nie alokację.

Śledzenie alokacji pamięci

W MFC, można użyć makra DEBUG_NEW zamiast właściwości Nowy przeciek operatora do lokalizowania pamięci.W wersji debugowania programu DEBUG_NEW przechowuje informacje o pliku nazwy i numerem wiersza dla każdego obiektu, który go przydziela.Kompilacja w wersji programu, DEBUG_NEW jest rozpoznawana jako prosty Nowy operacji bez nazwy i wierszu numer informacje o pliku.W związku z tym wykupić nie kary szybkość w wersji programu.

Jeśli nie chcesz ponownie zapisuje całego programu do użycia DEBUG_NEW zamiast właściwości Nowy, można zdefiniować tego makra w plikach źródłowych:

#define new DEBUG_NEW

Po wykonaniu zrzutu obiektu, każdy obiekt przydzielone z DEBUG_NEW Wyświetla liczbę plików i linii gdzie zostało przydzielone, co umożliwia wskazanie źródła przecieków pamięci.

Używa wersji debugowania struktury MFC DEBUG_NEW automatycznie, ale nie w kodzie.Jeśli chcesz skorzystać z DEBUG_NEW, należy użyć DEBUG_NEW jawnie lub #define nowy jak pokazano powyżej.

W tym temacie

Włączanie Diagnostyka pamięci

Aby móc używać funkcji Diagnostyka pamięci, należy włączyć diagnostyczne śledzenia.

Aby włączyć lub wyłączyć Diagnostyka pamięci

  • Wywoływanie funkcji globalnych AfxEnableMemoryTracking Aby włączyć lub wyłączyć alokatora diagnostycznych.Ponieważ diagnostyki pamięci są domyślnie w bibliotece debugowania, będą używane są zwykle ta funkcja tymczasowo je wyłączyć, przyspiesza wykonywanie programu i zmniejsza dane wyjściowe diagnostyki.

Aby wybrać określone pamięci funkcji diagnostycznych z afxMemDF

  • Jeśli chcesz bardziej precyzyjną kontrolę nad funkcji diagnostycznych pamięci, można wybiórczo włączyć pamięci poszczególnych funkcji diagnostycznych i wyłączanie funkcji przez ustawienie wartości zmiennych globalnych MFC afxMemDF.Ta zmienna może mieć następujące wartości określony przez wyliczany typ afxMemDF.

    Wartość

    Opis

    allocMemDF

    Włącz diagnostyczne alokatora (domyślnie).

    delayFreeMemDF

    Opóźnienie zwalnianiu pamięci podczas wywoływania delete lub free aż do zakończenia programu.Spowoduje to programu można przydzielić maksymalna ilość pamięci.

    checkAlwaysMemDF

    Wywołanie AfxCheckMemory za każdym razem, gdy pamięci jest przydzielany lub zwalniane.

    Te wartości można w połączeniu za pomocą operacji operatora logicznego OR, jak pokazano poniżej:

    afxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;
    

W tym temacie

Otwieranie migawki pamięci

  1. Utwórz CMemoryState obiektu, a następnie wywołać CMemoryState::Checkpoint funkcji elementu członkowskiego.Spowoduje to utworzenie pierwszą migawkę pamięci.

  2. Po program wykonuje operacje alokacji i dezalokacji jego pamięci, należy utworzyć inny CMemoryState obiektu, a następnie wywołać Checkpoint dla tego obiektu.To pobiera migawkę drugi zużycie pamięci.

  3. Tworzenie innego CMemoryState obiektu, a następnie wywołać jej CMemoryState::Difference funkcji elementu członkowskiego, dostarczanie jako argumenty dwa poprzednie CMemoryState obiektów.W przypadku różnic między Stanami dwóch pamięci Difference funkcja zwraca wartość różną od zera.Oznacza to, że który niektórych bloków pamięci ma nie alokację.

    W tym przykładzie pokazano, jak wygląda kod:

    // Declare the variables needed
    #ifdef _DEBUG
        CMemoryState oldMemState, newMemState, diffMemState;
        oldMemState.Checkpoint();
    #endif
    
        // Do your memory allocations and deallocations.
        CString s("This is a frame variable");
        // The next object is a heap object.
       CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
    
    #ifdef _DEBUG
        newMemState.Checkpoint();
        if( diffMemState.Difference( oldMemState, newMemState ) )
        {
            TRACE( "Memory leaked!\n" );
        }
    #endif
    

    Należy zauważyć, że instrukcje sprawdzania pamięci jest oddzielona przez #ifdef_DEBUG/ #endif blokuje tak, aby ich kompilacja jest tylko wtedy, gdy wersje programu do debugowania.

    Teraz, wiedząc już występuje przeciek pamięci, można użyć innej funkcji elementu członkowskiego, CMemoryState::DumpStatistics który pomoże Ci go znaleźć.

W tym temacie

Przeglądanie statystyki pamięci

CMemoryState::Difference funkcji sprawdza dwa obiekty stan pamięci i wykrywa wszystkie obiekty nie alokację ze stosu między Stanami początku i na końcu.Po wykonywane migawki pamięci i porównywany je przy użyciu CMemoryState::Difference, można wywołać metodę CMemoryState::DumpStatistics można pobrać informacji o obiektach, które nie zostały alokację.

Należy wziąć pod uwagę następującym przykładzie:

if( diffMemState.Difference( oldMemState, newMemState ) )
{
   TRACE( "Memory leaked!\n" );
   diffMemState.DumpStatistics();
}

Zrzut próbki z przykładu wygląda następująco:

0 bytes in 0 Free Blocks
22 bytes in 1 Object Blocks
45 bytes in 4 Non-Object Blocks
Largest number used: 67 bytes
Total allocations: 67 bytes

Bezpłatne bloki są bloków, którego dezalokacji zostanie opóźnione, jeśli afxMemDF została ustawiona w delayFreeMemDF.

Obiekt zwykłych bloków, pokazywaną w drugiej linii pozostają przydzielone na stosu.

Bloki obiektu nie obejmują tablic i struktury przydzielone z new.W takim przypadku cztery bloki niebędących obiektami przydzielone stosu, ale nie alokację.

Largest number used zapewnia maksymalną ilość pamięci używane przez program w dowolnym momencie.

Total allocations zapewnia całkowitej ilości pamięci używanej przez program.

W tym temacie

Dokonuje zrzutu obiektu pobierania

W programie MFC, można użyć CMemoryState::DumpAllObjectsSince do zrzut opis wszystkich obiektów na stosu, które nie zostały alokację.DumpAllObjectsSince dokonuje zrzutu wszystkie obiekty przydzielonych od czasu ostatniego CMemoryState::Checkpoint.Jeśli nie Checkpoint wywołanie miało miejsce, DumpAllObjectsSince dokonuje zrzutu wszystkie obiekty i nonobjects aktualnie w pamięci.

[!UWAGA]

Aby móc używać dumpingu obiektu MFC, musisz wykonać następujące czynności umożliwia śledzenie diagnostyczne.

[!UWAGA]

MFC automatycznie dokonuje zrzutu przecieku wszystkich obiektów, gdy program kończy pracę, dzięki czemu nie trzeba utworzyć kod w celu zrzut obiektów w tym momencie.

Poniższy kod sprawdza przeciek pamięci, porównując dwustanowy pamięci i dokonuje zrzutu wszystkie obiekty w przypadku wykrycia przeciek.

if( diffMemState.Difference( oldMemState, newMemState ) )
{
   TRACE( "Memory leaked!\n" );
   diffMemState.DumpAllObjectsSince();
}

Zawartość zrzut wyglądać w następujący sposób:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

Liczby w nawiasy na początku większości wierszy określić kolejność, w którym przydzielone obiekty.Obiekt najbardziej ostatnio przydzielone najwyższym numerze i pojawi się u góry zrzut.

Aby uzyskać maksymalną ilość informacji poza zrzutu obiektu, można zastąpić Dump funkcji elementu członkowskiego w dowolnej CObject-opracowane na obiekt, aby dostosować zrzutu obiektu.

Można ustawić punkt przerwania na alokacji pamięci określonego przez ustawienie zmiennej globalnej _afxBreakAlloc do liczby podanej w nawiasy klamrowe.Jeśli ponownie program debuger spowoduje przerwanie wykonywania po tej alokacji.Następnie można wyświetlać na stosie wywołań, aby zobaczyć, jak program, które otrzymały do tego punktu.

Biblioteka czasu C ma podobne funkcje, _CrtSetBreakAlloc, można użyć dla C alokacji czasu wykonywania.

W tym temacie

Interpretacja pamięci dokonuje zrzutu

Przyjrzyj się zrzutu ten obiekt bardziej szczegółowo:

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

{1} strcore.cpp(80) : non-object block at $00A7516E, 25 bytes long

Program wygenerowania tego zrzutu istniało tylko dwóch alokacji jawnego — na stosie i jeden na stosu:

// Do your memory allocations and deallocations.
CString s("This is a frame variable");
// The next object is a heap object.
CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );

CPerson Konstruktor ma trzy argumentów, które są wskaźnikami do char, które są używane do zainicjowania CString zmienne elementu członkowskiego.Zrzut pamięci zawiera CPerson obiektu wraz z trzech bloków nonobject (3, 4 i 5).Są przechowywane na znaki CString Zmienne składowe i nie można usunąć po CPerson destruktora obiektu jest wywoływany.

Liczba bloków 2 jest CPerson sam obiekt.$51A4 reprezentuje adres bloku i następuje zawartości obiektu, które zostały danych wyjściowych przez CPerson::Dump wtedy, gdy DumpAllObjectsSince.

Przypuszczalnie, że bloku o numerze 1 jest skojarzony z CString Zmienna ramki z powodu jej numer sekwencji i wielkości, która jest zgodna z liczbą znaków w ramach CString zmiennej.Zmienne przydzielone ramki są automatycznie alokację, gdy ramki wykracza poza zakres.

Zmienne ramki

Ogólnie rzecz biorąc mogą nie występować obiektów stosu skojarzone z ramki zmienne, ponieważ są automatycznie alokację zmienne ramki przejścia poza zakresem.Aby uniknąć bałaganu w swojej diagnostyczne zrzuty pamięci, należy umieścić wywołaniami Checkpoint aby były poza zakresem ramki zmiennych.Na przykład umieścić w nawiasach zakresu poprzedni kod alokacji, jak pokazano poniżej:

oldMemState.Checkpoint();
{
    // Do your memory allocations and deallocations ...
    CString s("This is a frame variable");
    // The next object is a heap object.
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
}
newMemState.Checkpoint();

Z zakresu nawiasów w miejscu zrzut pamięci w tym przykładzie są następujące:

Dumping objects ->

{5} strcore.cpp(80) : non-object block at $00A7521A, 9 bytes long
{4} strcore.cpp(80) : non-object block at $00A751F8, 5 bytes long
{3} strcore.cpp(80) : non-object block at $00A751D6, 6 bytes long
{2} a CPerson at $51A4

Last Name: Smith
First Name: Alan
Phone #: 581-0215

Przydziały nonobject

Zwróć uwagę, że są niektóre obiekty (takie jak CPerson), a inne alokacji nonobject. "Nonobject "są alokacji dla obiektów nie pochodzi od CObject lub przydziałów typów pierwotnych C, takich jak char, int, lub długi.Jeśli CObject -klasy pochodnej przydziela dodatkowe miejsce, takie jak dla wewnętrznego buforów tych obiektów wyświetla zarówno obiekt, jak i nonobject alokacji.

Zapobieganie przecieków pamięci

Uwaga w kodzie powyżej, że blok pamięci skojarzone z CString zmiennej ramki automatycznie alokację i nie jest wyświetlany jako przeciek pamięci.Automatyczne dezalokacji skojarzone z zakresu reguły wykonuje te automatycznie skojarzone z zmienne ramki większością przecieków pamięci.

Przydzielone stosu obiektów jednak należy jawnie usunąć obiekt, aby zapobiec przeciek pamięci.Aby wyczyścić ostatnich przeciek pamięci w poprzednim przykładzie, Usuń CPerson obiektu przydzielone na stosie, w następujący sposób:

{
    // Do your memory allocations and deallocations.
    CString s("This is a frame variable");
    // The next object is a heap object.
    CPerson* p = new CPerson( "Smith", "Alan", "581-0215" );
    delete p;
}

W tym temacie

Dokonuje zrzutu Dostosowywanie obiektu

Kiedy wyprowadzić klasę z CObject, można zastąpić Dump funkcji elementu członkowskiego, aby podać dodatkowe informacje, gdy użytkownik korzysta z DumpAllObjectsSince do obiektów zrzutu okno dane wyjściowe.

Dump Funkcji zapisuje tekstowa reprezentacja elementu członkowskiego obiektu zmienne w kontekście zrzutu (CDumpContext).Kontekst zrzutu jest podobny do strumienia we/wy.Można użyć operatora Dołącz (<<) do wysyłania danych do CDumpContext.

Jeśli zastąpienie Dump funkcji, należy najpierw wywołać wersja klasa podstawowa Dump do zrzutu zawartości obiektu klasy podstawowej.Następnie danych wyjściowych tekstowy opis i wartości poszczególnych zmiennych elementu członkowskiego klasy pochodnej.

Deklaracja Dump funkcji wygląda następująco:

class CPerson : public CObject
{
public:
#ifdef _DEBUG
    virtual void Dump( CDumpContext& dc ) const;
#endif

    CString m_firstName;
    CString m_lastName;
    // And so on...
};

Ponieważ tylko obiekt dumpingu najwygodniejszy sposób podczas debugowania programu, deklaracji Dump funkcji jest oddzielona z #ifdef _DEBUG / #endif bloku.

W poniższym przykładzie Dump pierwszego wywołania funkcji Dump funkcji dla danej klasy podstawowej.Następnie zapisuje krótki opis poszczególnych zmiennych elementu członkowskiego wraz z wartości element członkowski w strumieniu diagnostycznych.

#ifdef _DEBUG
void CPerson::Dump( CDumpContext& dc ) const
{
    // Call the base class function first.
    CObject::Dump( dc );

    // Now do the stuff for our specific class.
    dc << "last name: " << m_lastName << "\n"
        << "first name: " << m_firstName << "\n";
}
#endif

Należy podać CDumpContext argument, aby określić, gdzie dane wyjściowe zrzutu.Wersja debugowania MFC dostarcza wstępnie zdefiniowanych CDumpContext obiekt o nazwie afxDump który wysyła dane wyjściowe do debugowania.

CPerson* pMyPerson = new CPerson;
// Set some fields of the CPerson object.
//...
// Now dump the contents.
#ifdef _DEBUG
pMyPerson->Dump( afxDump );
#endif

W tym temacie

Zmniejszyć rozmiar Kompilacja debugowania MFC

Informacje o debugowaniu dla dużych aplikacji MFC może zająć dużo miejsca na dysku.Można użyć jednej z tych procedur, aby zmniejszyć rozmiar:

  1. Odbudowy bibliotek MFC przy użyciu /Z7, /Zi, /ZI (Format informacji o debugowaniu) opcji, zamiast /Z7.Te opcje tworzenia plik bazy danych (PDB) jeden program, który zawiera informacje debugowania dla całej biblioteki zmniejszenie redundancji i zapisywanie miejsca.

  2. Odbudowy biblioteki MFC bez informacje o debugowaniu (nie /Z7, /Zi, /ZI (Format informacji o debugowaniu) opcji).W przypadku braku informacje debugowania uniemożliwi przy użyciu większości funkcji debuger kodem biblioteki MFC, ale ponieważ biblioteki MFC są już dokładnie debugowane, nie może to być problem.

  3. Tworzenie aplikacji z informacjami debugowania dla wybranych modułów tylko opisane poniżej.

W tym temacie

Tworzenie aplikacji MFC z informacje debugowania dla wybranych modułów

Tworzenie wybrane moduły z bibliotekami debugowania MFC umożliwia na używanie krok i inne urządzenia debugowania w tych modułach.Ta procedura korzysta z obu debugowania i zwolnij tryby Visual C++ pliku reguł programu make, co wymaga zmiany opisane w następujące kroki (i również wprowadzania "odbudowy wszystkie" konieczne, gdy wymagany jest pełny kompilacji wersji).

  1. W Eksploratorze rozwiązań wybierz projekt.

  2. Z widoku menu, wybierz opcję stron właściwości.

  3. Najpierw należy utworzyć nową konfigurację projektu.

    1. W < projektu > strony właściwości okno dialogowe, kliknij przycisk programu Configuration Manager przycisku.

    2. W okno dialogowe programu Configuration Manager, Znajdź projekt w siatce.W konfiguracji kolumny, wybierz opcję < nowy... >.

    3. W okno dialogowe Nowy projekt konfiguracji, wpisz nazwę dla nowej konfiguracji, takich jak "Częściowy debugowanie", w Nazwa konfiguracji projektu pola.

    4. W Skopiuj ustawienia z wybierz wersji.

    5. Kliknij przycisk OK zamknąć nowej konfiguracji projektuokno dialogowe.

    6. Zamknij programu Configuration Manager okno dialogowe.

  4. Teraz zostanie ustawiony opcje dla całego projektu.

    1. W stron właściwości okna dialogowego Właściwości konfiguracji folder, wybierz opcję Ogólne kategorii.

    2. W siatce ustawień projektu, rozwiń węzeł domyślne ustawienia projektu (w razie potrzeby).

    3. W obszarze domyślne ustawienia projektu, Znajdź Użyj MFC.Bieżące ustawienia pojawia się w prawej kolumnie siatki.Polecenie bieżące ustawienia i zmień je do MFC używany w bibliotece statycznych.

    4. W lewym okienku stron właściwości po otwarciu okna dialogowego C/C++ i wybierz polecenie preprocesora.W siatce właściwości Znajdź Definicje preprocesora i Zamień "NDEBUG" na "_DEBUG".

    5. W lewym okienku stron właściwości po otwarciu okna dialogowego Łączenie i wybierz polecenie dane wejściowe kategorii.W siatce właściwości Znajdź dodatkowe zależności.W dodatkowe zależności ustawienie, wpisz "NAFXCWD.Biblioteka"i"LIBCMT."

    6. Kliknij przycisk OK Aby zapisać nowe opcje kompilacji i zamknąć stron właściwości okno dialogowe.

  5. Z Tworzenie menu, wybierz opcję odbudowy.Usuwa wszystkie informacje debugowania z moduły, ale nie ma wpływu na bibliotece MFC.

  6. Teraz należy dodać informacje debugowania do wybranych modułów w aplikacji.Należy pamiętać, że można Ustawianie punktów przerwania i korzystać z innych funkcji debuger tylko wtedy, gdy modułów, które zostały skompilowane informacje debugowania.Dla każdego pliku projektu, w którym mają zostać uwzględnione informacje debugowania, wykonaj następujące kroki:

    1. Otwórz w Eksploratorze rozwiązań plikach źródłowych folder umieszczony w projekcie.

    2. Wybierz plik, aby ustawić informacje debugowania dla.

    3. Z widoku menu, wybierz opcję stron właściwości.

    4. W stron właściwości okna dialogowego Ustawienia konfiguracji folder, otwórz C/C++ następnie wybierz folder Ogólne kategorii.

    5. W siatce właściwości Znajdź Format informacje debugowania.

    6. Kliknij przycisk Format informacje debugowania ustawienia, a następnie wybierz odpowiednią opcję (zazwyczaj /ZI) dla informacje debugowania.

    7. Jeśli używasz aplikacji wygenerowane przez Kreatora aplikacji lub mieć wstępnie skompilowany nagłówki, należy wyłączyć wstępnie skompilowanej nagłówki lub ponownie skompilować je przed kompilacji w innych modułach.W przeciwnym razie zostanie wyświetlony ostrzeżenie C4650 i komunikat o błędzie C2855.Można wyłączyć wstępnie skompilowanej nagłówki, zmieniając tworzenia/używania wstępnie skompilowanej nagłówki w < projektu > właściwości okno dialogowe (Właściwości konfiguracji folderu, C/C++ podfolderu, wstępnie skompilowanej nagłówki kategorii).

  7. Z Tworzenie menu, wybierz opcję Tworzenie odbudować pliki projektu, które są nieaktualne.

Jako alternatywę dla techniki opisane w tym temacie, można użyć pliku reguł programu make zewnętrznego do definiowania poszczególne opcje dla każdego pliku.W takim przypadku można połączyć z bibliotekami debugowania MFC, musisz zdefiniować _DEBUG Flaga dla każdego modułu.Jeśli chcesz użyć MFC wersji biblioteki, należy zdefiniować NDEBUG.Aby uzyskać więcej informacji na temat pisania zewnętrzne pliki reguł programu make, zobacz odwołania NUPEWNIJ.

W tym temacie

Zobacz też

Inne zasoby

Debugowanie Visual C++