Sdílet prostřednictvím


Techniky ladění MFC

Pokud jsou ladění aplikace MFC, může být užitečné tyto techniky ladění.

V tomto tématu

AfxDebugBreak

The trasování macro

Detekce nevracení paměti v knihovně MFC

  • Sledování přidělení paměti

  • Povolení diagnostiku paměti

  • Pořizování snímků paměti

  • Zobrazení statistiky paměti

  • Vypíše objekt odběr

    • Vypíše výklad paměti

    • Vypíše úpravy objektu

    Zmenšit velikost sestavení ladění MFC

    • Vytváření MFC aplikace s informacemi o ladění pro vybrané moduly

AfxDebugBreak

Knihovna MFC poskytuje zvláštní AfxDebugBreak funkci pro pevné kódování zarážky ve zdrojovém kódu:

AfxDebugBreak( );

Na platformách Intel AfxDebugBreak vytváří následující kód, která dělení ve zdroji kódu a jádro kódu:

_asm int 3

Na dalších platformách AfxDebugBreak pouze volá DebugBreak.

Ujistěte se, chcete-li odebrat AfxDebugBreak příkazů při vytváření o verzi sestavení nebo použít #ifdef _DEBUG k jejich uzavřít.

V tomto tématu

TRASOVÁNÍ makra

Pro zobrazení zprávy ve svém programu v ladicí program okně výstupu, můžete použít ATLTRACE makra nebo MFC trasování makra.Podobně jako kontrolní výrazy, makra trasování jsou aktivní pouze ve verzi ladění vašeho programu a zmizí při kompilaci v prodejní verzi.

Následující příklady ukazují způsoby, můžete použít trasování makra.Podobně jako printf, trasování macro dokáže zpracovat počet argumentů.

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 );

TRASOVÁNÍ makra správně zpracovává znak * i wchar_t * parametry.Následující příklady ukazují použití makra trasování společně s různé typy parametrů řetězce.

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);

Další informace týkající trasování macro, naleznete v části Diagnostické služby.

V tomto tématu

Zjištění paměť nevrací v knihovně MFC

Knihovna MFC poskytuje třídy a funkce pro zjišťování paměti, která je přidělen, ale nikdy navrácen.

Sledování přidělení paměti

Knihovna MFC, můžete v makra DEBUG_NEW místo nové nevrací operátor k vyhledání paměti.V ladicí verzi programu si DEBUG_NEW si udržuje přehled o číslo, pro každý objekt, který přiděluje název a řádek souboru.Při kompilaci prodejní verzi programu si DEBUG_NEW přeloží na jednoduchou nové operace bez názvu a řádku číselné informace o souboru.Proto platíte žádné snížení rychlosti v prodejní verzi aplikace.

Pokud nechcete přepsat celý váš program používat DEBUG_NEW místo nové, můžete definovat tohoto makra ve zdrojových souborech:

#define new DEBUG_NEW

Při provedení objekt výpisu, každý objekt přidělené s DEBUG_NEW se zobrazí číslo soubor a řádek, kde byla přiděleno, umožní vám přesně určit zdroje nevracením paměti.

Ladicí verze rozhraní MFC používá DEBUG_NEW automaticky, ale nikoli váš kód.Pokud chcete, aby výhody DEBUG_NEW, je nutné použít DEBUG_NEW explicitně nebo #define nový jak je uvedeno výše.

V tomto tématu

Povolení diagnostiku paměti

Před použitím zařízení diagnostiku paměti, je nutné povolit diagnostické trasování.

Chcete-li povolit nebo zakázat diagnostiku paměti

  • Zavolejte funkci globální AfxEnableMemoryTracking k povolení nebo zakázání přidělení paměti diagnostiky.Vzhledem k tomu, že diagnostiku paměti jsou ve výchozím v knihovně ladění, obvykle použijete tuto funkci dočasně vypnout, což zvyšuje rychlost vykonávání programu a snižuje výstup diagnostiky.

Chcete-li vybrat konkrétní paměti diagnostických funkcí s afxMemDF

  • Pokud chcete, aby přesnější kontrolu nad diagnostických funkcí paměti, můžete výběrově zapnout diagnostických funkcí jednotlivých paměti zapnutí a vypnutí tak, že nastavíte hodnotu globální proměnné MFC afxMemDF.Tato proměnná může mít následující hodnoty podle výčtového typu afxMemDF.

    Hodnota

    Popis

    allocMemDF

    Zapněte přidělení diagnostiky paměti (výchozí).

    delayFreeMemDF

    Zpoždění uvolňování paměti při volání delete nebo free až do konce programu.To způsobí, že je váš program přidělit maximální množství paměti.

    checkAlwaysMemDF

    Volání AfxCheckMemory pokaždé, když je přiděleno nebo uvolnění paměti.

    Tyto hodnoty lze použít v kombinaci pomocí operace logického OR, jak je znázorněno zde:

    afxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;
    

V tomto tématu

Pořizování snímků paměti

  1. Vytvořit CMemoryState objekt a volání CMemoryState::Checkpoint členské funkce.Tím se vytvoří první snímek paměti.

  2. Poté, co váš program provede její paměti přidělené a odebrané operace, vytvořit další CMemoryState objekt a volání Checkpoint pro tento objekt.To získá druhý snímek využití paměti.

  3. Vytvořit třetí CMemoryState objekt a volání jeho CMemoryState::Difference funkci člen, poskytující jako argumenty dva předchozí CMemoryState objekty.Pokud je rozdíl mezi dvěma paměti stavy, Difference Funkce vrátí nenulovou hodnotu.To znamená, které nebyly byl navrácen některé bloky paměti.

    Tento příklad ukazuje, jak vypadá kód:

    // 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
    

    Všimněte si, že kontrola paměti příkazy jsou závorkách podle #ifdef_DEBUG/ #endif blokuje tak, aby jsou zkompilovány pouze v ladicí verze aplikace.

    Nyní, když už víte, existuje nevracení paměti, jiné funkci člena, můžete použít CMemoryState::DumpStatistics které vám pomohou vyhledat.

V tomto tématu

Zobrazení statistiky paměti

CMemoryState::Difference funkce zjistí dva objekty stavu paměti a zjišťuje všechny objekty není odebrána z haldy mezi stavy zahájení a ukončení.Po provedených snímky paměti a jejich porovnání pomocí CMemoryState::Difference, můžete volat CMemoryState::DumpStatistics mají být získány informace o objektech, které nebyly byl navrácen.

Zvažte následující příklad:

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

Ukázky výpis z příkladu vypadá nějak takto:

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

Volné bloky jsou bloky, jejichž navracení zpět dojde ke zpoždění Pokud afxMemDF byla nastavena na delayFreeMemDF.

Přidělená do haldy i nadále běžných objekt bloků, uvedeny na druhém řádku.

Objekt bez bloky patří pole a struktury přiřazený s new.V takovém případě čtyři bloky jiný objekt byly přiděleny na haldy, ale není navrácen.

Largest number used poskytuje maximální velikost paměti používá program kdykoli znovu.

Total allocations přiřadí celkovou velikost paměti používá program.

V tomto tématu

Vypíše objekt odběr

V aplikaci MFC – můžete použít CMemoryState::DumpAllObjectsSince pro výpis popis všech objektů do haldy, které nebyly byl navrácen.DumpAllObjectsSince Vypíše všechny objekty přiděleny od posledního CMemoryState::Checkpoint.Pokud ne Checkpoint volání proběhla, DumpAllObjectsSince Vypíše všechny objekty a nonobjects v současnosti v paměti.

[!POZNÁMKA]

Před použitím MFC objekt rozpětí, je nutné Povolit trasování diagnostiky.

[!POZNÁMKA]

Knihovna MFC automaticky vypíše všechny prozrazený objekty při ukončení aplikace, takže není nutné vytvořit kód pro výpis objekty v tomto bodě.

Následující kód testuje nevracení paměti porovnáním dvou stavů paměti a vypíše všechny objekty, je-li nevracení zjištěn.

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

Obsah výpis stavu vypadat například takto:

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

Čísla do složených závorek na začátku většina řádky určit pořadí, ve kterém byly objekty přiděleny.Nedávno přidělené objekt s nejvyšším číslem a zobrazí se v horní části výpis stavu.

Chcete-li získat maximální množství informací z výpisu objekt, můžete přepsat Dump členské funkce ze všech CObject-odvozeného objektu k přizpůsobení výpis stavu objektu.

Nastavením globální proměnné lze nastavit zarážky na přidělení paměti konkrétní _afxBreakAlloc k číslu do složených závorek.Je-li znovu spusťte program, ladicí program přerušit provádění když takové přidělování probíhá.Poté můžete prohlédnout zásobník volání, abyste viděli, jak svůj program máte k tomuto bodu.

Knihovna C run-time má podobnou funkci, _CrtSetBreakAlloc, které můžete pro přidělení C run-time.

V tomto tématu

Vypíše výklad paměti

Podívejte se na tento objekt výpisu podrobněji:

{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, který generované tohoto výpisu obsahovalo pouze dva explicitní přidělení – jednu na zásobníku a jeden do haldy:

// 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 přebírá tři argumenty, které jsou odkazy na char, které se používají k inicializaci CString proměnné členů.V výpis stavu paměti, se zobrazí CPerson objekt společně s tří nonobject bloků (3, 4 a 5).Tyto obsahovat znaky pro CString proměnné členů a nebudou odstraněny při CPerson vyvolání destruktoru objektu.

Číslo bloku 2 je CPerson samotného objektu.$51A4 představuje adresu bloku a po kterém následuje obsah objektu, které byly výstupních podle CPerson::Dump Při volání DumpAllObjectsSince.

Můžete uhodnout přidružený bloku číslo 1 CString rámec proměnné z důvodu jeho pořadové číslo a velikosti, která odpovídá počet znaků v rámci CString proměnné.Proměnné přiděleny na snímku jsou automaticky navrácen při rámce mimo rozsah.

Rámec proměnné

Obecně by neměl starosti haldy objekty přidružený k proměnné rámec vzhledem k tomu, že jsou automaticky uvolněna při proměnné rámec přejít mimo rozsah.Chcete-li předejít zbytečné soubory ve vaší diagnostiky výpisy paměti, by měl umístit své volání Checkpoint tak, aby byly mimo rozsah rámec proměnné.Můžete například do hranatých závorek oboru v předchozí přidělení kódu, jak je znázorněno zde:

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();

Hranatých závorek oboru na místě výpis stavu paměti v tomto příkladu je následující:

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

Nonobject přidělení

Všimněte si, že některé přidělení jsou objekty (například CPerson) a některé jsou nonobject rozdělení. "Nonobject přidělení"jsou přidělení pro objekty, které není odvozen od CObject nebo přidělení primitivní typy C jako char, int, nebo dlouhé.Pokud třídy CObject -odvozené třídy přidělí další místo, jako je například pro vnitřní vyrovnávací paměti, ty objekty, které se zobrazí objekt a nonobject přidělení.

Prevence nevracením paměti

Všimněte si z kódu výše, že blok paměti přidružený CString rámec proměnné má automaticky odebrána a není uveden jako nevracení paměti.Většina nevracením paměti přidružený k proměnné rámec postará automatické navracení zpět přidružené k vymezení pravidel.

Pro objekty přiděleny na haldy nicméně je nutné explicitně odstranit objekt, který chcete-li zabránit nevracení paměti.Chcete-li vyčistit poslední nevracení paměti v předchozím příkladu, odstraňte CPerson objektu přidělen do haldy takto:

{
    // 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;
}

V tomto tématu

Vypíše úpravy objektu

Pokud odvodíte třídu od třídy třídy CObject, můžete přepsat Dump členské funkce pro poskytnutí dalších informací, když použijete DumpAllObjectsSince k výpisu objektů okně výstupu.

Dump Funkce zapisuje textová reprezentace objektu člena proměnné do kontextu dump (CDumpContext).Kontext výpisu se podobá vstupně-výstupní datový proud.Operátor append můžete použít (<<) k odeslání dat CDumpContext.

Při přepsání Dump funkce, měli byste nejprve volat základní třída verze Dump pro výpis obsah objektu základní třídy.Ve výstupu textový popis a hodnota pro každou proměnnou člen vaší odvozené třídy.

Prohlášení o Dump funkce vypadá nějak takto:

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

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

Vzhledem k tomu, že objekt rozpětí smysl pouze při ladění svůj program prohlášení o Dump funkce je závorkách s #ifdef _DEBUG / #endif bloku.

V následujícím příkladu Dump první volání funkce Dump funkci pro jeho základní třídy.Poté zapíše krátký popis pro každou proměnnou člena spolu s hodnotu člena s hodnotou do diagnostických datového proudu.

#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

Je třeba zadat CDumpContext argument, chcete-li určit, kde budou přenášeny výstup dump.Ladicí verze MFC poskytuje předdefinované šablony CDumpContext objekt s názvem afxDump odešle výstup ladicí program.

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

V tomto tématu

Zmenšit velikost sestavení ladění MFC

Informace o ladění pro velké MFC aplikace může trvat až velké množství místa na disku.Jeden z následujících kroků můžete zmenšit velikost:

  1. Znovu vytvořit pomocí knihovny MFC /Z7, /Zi, /ZI (formát ladicích informací) možnost, namísto /Z7.Tyto možnosti vytvořit soubor databáze (PDB) jednoduchý program, který obsahuje informace o ladění pro celou knihovnu snížení redundance a ukládání místa.

  2. Znovu vytvořit knihovny MFC bez informace o ladění (žádný /Z7, /Zi, /ZI (formát ladicích informací) možnost).V takovém případě nedostatku informace o ladění zabrání pomocí většiny možností ladicí program v rámci kódu knihovny MFC, ale vzhledem k tomu, že knihovny MFC jsou již důkladně ladění, nesmí to být problém.

  3. Vytvoříte vlastní aplikaci se informace o ladění pro vybrané moduly, jak je popsáno níže.

V tomto tématu

Vytváření MFC aplikace s informacemi o ladění pro vybrané moduly

Vytváření vybraného moduly s ladění knihoven MFC umožňuje vám umožní využít krokování a ladění zařízení v těchto modulech.Tento postup zabrání v používání obou ladění a uvolněte režimy soubor pravidel Visual C++, což nutně vyžaduje změn popsaných v následujících kroků (a také vytváření "znovu vytvořit všechny" potřeby při plné verze sestavení je třeba zadat).

  1. V Průzkumníku řešení vyberte projekt.

  2. Z zobrazení klepněte na příkaz stránky vlastností.

  3. Nejprve vytvoříte novou konfiguraci projektu.

    1. V < Projekt > stránky vlastností dialogového okna, klikněte na tlačítko nástroje Configuration Manager tlačítko.

    2. V dialogové okno nástroje Configuration Manager, vyhledejte svůj projekt v mřížce.V Konfigurace sloupec, vyberte možnost < nový... >.

    3. V dialogové okno Nový projekt konfigurace, zadejte název nové konfigurace, například "Částečné ladit", do název konfigurace projektu pole.

    4. V Kopírovat nastavení z seznam, zvolte verze.

    5. Klikněte na tlačítko OK zavřete nové konfigurace projektudialogového okna.

    6. Zavřít nástroje Configuration Manager dialogového okna.

  4. Nyní bude nastavení možností pro celý projekt.

    1. V stránky vlastností dialogové okno, v části Vlastnosti konfigurace složku, vyberte možnost Obecné kategorie.

    2. V mřížce nastavení projektu, rozbalte položku výchozí projekt (v případě potřeby).

    3. V části výchozí projekt, Najít Použití knihovny MFC.Aktuální nastavení se zobrazí v pravém sloupci mřížky.Klikněte na aktuální nastavení a změňte ho na Použití knihovny MFC ve statické knihovně.

    4. V levém podokně Vlastnosti stránky otevřete dialogové okno C/C++ složku a vyberte Preprocessor.V mřížce vlastnosti najít Preprocessor definice a "NDEBUG" nahradit "_DEBUG".

    5. V levém podokně Vlastnosti stránky otevřete dialogové okno Linkeru složku a vyberte možnost vstup kategorie.V mřížce vlastnosti najít Další závislosti.V Další závislosti nastavení, zadejte "NAFXCWD.LIB"a"LIBCMT."

    6. Klikněte na tlačítko OK zavřete a uložte nové možnosti sestavení stránky vlastností dialogového okna.

  5. Z sestavení klepněte na příkaz znovu vytvořit.Odebere všechny informace o ladění z moduly, ale nemá vliv na knihovnu MFC.

  6. Nyní je nutné přidat informace o ladění zpět do vybrané moduly ve vaší aplikaci.Mějte na paměti, můžete nastavit zarážky a dalších funkcí ladicí program provádět pouze v moduly, které mají kompilována s ladicími informacemi.Pro každý projekt soubor, do kterého chcete zahrnout informace o ladění, provede následující kroky:

    1. V Průzkumníku řešení otevřete zdrojové soubory složka umístěna v rámci vašeho projektu.

    2. Vyberte soubor, který chcete nastavit informace o ladění pro.

    3. Z zobrazení klepněte na příkaz stránky vlastností.

    4. V stránky vlastností dialogové okno, v části Nastavení konfigurace složky, otevřete C/C++ vyberte složku Obecné kategorie.

    5. V mřížce vlastnosti najít Debug Information Format.

    6. Klikněte na tlačítko Debug Information Format nastavení a vyberte požadované možnosti (obvykle /ZI) pro informace o ladění.

    7. Pokud používáte aplikaci generované průvodcem aplikace nebo mít předkompilované hlavičky, je třeba vypnout předkompilované hlavičky nebo jejich zkompilovat před kompilací dalších modulů.Jinak obdržíte upozornění C4650 a chybová zpráva C2855.Předkompilované hlavičky lze vypnout změnou Vytvoření/použití předkompilovaných hlaviček nastavení v < Projekt > vlastnosti dialogového okna (Vlastnosti konfigurace složku, C/C++ podsložky, Předkompilované hlavičky kategorie).

  7. Z sestavení klepněte na příkaz sestavení znovu sestavit soubory projektu, které jsou zastaralá.

Jako alternativa k technika popsané v tomto tématu, můžete definovat jednotlivé možnosti pro každý soubor externí soubor pravidel.V takovém případě Pokud chcete propojit s knihoven MFC ladění, je nutné definovat _DEBUG příznak pro každý modul.Pokud chcete použít verze knihoven MFC, je nutné definovat NDEBUG.Další informace o psaní externí soubory pravidel naleznete NOVĚŘTE referenční.

V tomto tématu

Viz také

Další zdroje

Ladění Visual C++