Sdílet prostřednictvím


Techniky ladění MFC

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

V tomto tématu

AfxDebugBreak

Makro trasování

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

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

  • Povolení Diagnostika paměti

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

  • Zobrazení statistiky paměti

  • Vypíše objekt odběru

    • Interpretace paměti vypíše

    • Vypíše úpravy objektu

    Zmenšení velikosti sestavení pro ladění MFC

    • Vytvoření knihovny MFC aplikace s ladicími informacemi pro vybrané moduly

AfxDebugBreak

Knihovna MFC poskytuje zvláštní AfxDebugBreak funkci pro pevné kódování body přerušení ve zdrojovém kódu:

AfxDebugBreak( );

Na platformě Intel AfxDebugBreak vytvoří následující kód, která dělení ve zdrojovém kódu namísto kódu jádra:

_asm int 3

Na ostatních platformách AfxDebugBreak pouze volá DebugBreak.

Nezapomeňte odebrat AfxDebugBreak příkazy, vytvoříte-li k uvolnění sestavení nebo pomocí #ifdef _DEBUG k jejich uzavření.

V tomto tématu

Makro trasování

Chcete-li zobrazit zprávy z aplikace v ladicím programu okno výstup, můžete použít ATLTRACE makro nebo knihovny MFC trasování makro.Stejně jako výrazy, makra trasování jsou aktivní pouze v ladicí verzi programu a zmizí při kompilaci v prodejní verze.

Následující příklady ukazují některé způsoby použití trasování makro.Stejně jako printf, trasování makro může zpracovávat 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 );

Makro trasování odpovídajícím způsobem zpracovává parametry char * i wchar_t *.Následující příklady demonstrují použití makra trasování, jakož i 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í makro, viz Diagnostické služby.

V tomto tématu

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

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

7sx52ww7.collapse_all(cs-cz,VS.110).gifSledování přidělení paměti

V knihovně MFC, můžete použít makro DEBUG_NEW místo nové nevrací operátor k vyhledání paměti.Ladicí verze aplikace sady DEBUG_NEW uchovává informace o souboru číslo název a řádek pro každý objekt, který přiděluje.Při kompilaci verzi programu, DEBUG_NEW řeší jednoduché nové operace bez soubor název a řádek číselné informace.Tedy platit žádné snížení rychlosti ve verzi programu.

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

#define new DEBUG_NEW

Při provedení objekt dump, každý objekt přidělena s DEBUG_NEW se zobrazí soubor a číslo řádku, kde byla přidělena, umožňuje zdůraznit zdrojů nevracení paměti.

Ladicí verze knihovny MFC framework používá DEBUG_NEW automaticky, ale váš kód nepotřebuje.Pokud chcete, aby výhody DEBUG_NEW, je nutné použít DEBUG_NEW výslovně nebo # definovat nové jak je uvedeno výše.

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifPovolení Diagnostika paměti

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

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

  • Volání globální funkce AfxEnableMemoryTracking Chcete-li povolit nebo zakázat přidělování diagnostiku paměti.Protože nástroj Diagnostika paměti na ve výchozím nastavení v knihovně ladění, obvykle použijete tuto funkci dočasně vypnout, což zvyšuje rychlost vykonávání programu a snižuje diagnostické výstupu.

Chcete-li vybrat konkrétní paměti diagnostické funkce s afxMemDF

  • Pokud chcete přesnější kontrolu nad diagnostické funkce paměti, můžete selektivně zapnout jednotlivé paměti diagnostické funkce zapínat a vypínat tak, že nastavíte hodnotu globální proměnné knihovny MFC afxMemDF.Tato proměnná může nabývat následujících hodnot podle Výčtový typ afxMemDF.

    Value

    Description

    allocMemDF

    Zapněte diagnostiku paměti přidělování (výchozí).

    delayFreeMemDF

    Zpoždění uvolnění paměti při volání delete nebo free dokud ukončí program.To způsobí, že program přidělit maximální možné množství paměti.

    checkAlwaysMemDF

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

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

    afxMemDF = allocMemDF | delayFreeMemDF | checkAlwaysMemDF;
    

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifPořizování snímků paměti

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

  2. Poté, co program provede její paměti přidělování a navracení zpět operace, vytvořit další CMemoryState objekt a volání Checkpoint pro daný objekt.Tím získá druhý snímek využití paměti.

  3. Třetí CMemoryState objekt a volání jeho CMemoryState::Difference členskou funkci jako argumenty dodávající dva předchozí CMemoryState objekty.Pokud je rozdíl mezi státy dvě paměti Difference funkce vrátí nenulovou hodnotu.To znamená, že, nebyly některé bloky paměti navrácen.

    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 příkazy kontrolu paměti jsou bracketed podle #ifdef_DEBUG/ #endif blokuje, takže jsou kompilovány pouze v ladicí verze aplikace.

    Nyní, když víte, existuje nevracení paměti, můžete použít jiné členské funkce CMemoryState::DumpStatistics, na Zobrazení statistiky paměti , můžete jej vyhledat.

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifZobrazení statistiky paměti

CMemoryState::Difference Funkce porovná dva objekty stavu paměti a rozpozná všechny objekty, které není odebrána z haldy mezi státy začátek a konec.Po přijata paměti snímků a jejich porovnání pomocí CMemoryState::Difference, můžete volat CMemoryState::DumpStatistics Chcete-li získat informace o objektech, které nebyly byl navrácen.

Příklad:

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

Ukázka výpisu z příkladu vypadá 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 je zpožděný, pokud afxMemDF byl nastaven na delayFreeMemDF.

Běžný objekt bloky, na druhém řádku zůstat přidělené na haldě.

Bloky Non objekt patří polí a struktur přidělené s new.V tomto případě čtyři neobjektově-bloky byly přiděleny na haldě modulu, ale není platný.

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

Total allocationsUvádí celkové množství paměti, které program používá.

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifVypíše objekt odběru

V aplikaci knihovny MFC lze pomocí CMemoryState::DumpAllObjectsSince pro výpis popis všech objektů na haldě, které nebyly byl navrácen.DumpAllObjectsSinceVypíše všechny objekty, které jsou přiděleny od posledního CMemoryState::Checkpoint.Pokud ne Checkpoint volání uskutečnil, DumpAllObjectsSince vypíše všechny objekty a nonobjects aktuálně v paměti.

[!POZNÁMKA]

Před použitím dumpingu objektu knihovny MFC, musíte Povolení diagnostické trasování.

[!POZNÁMKA]

Knihovna MFC automaticky vypíše všechny prozrazený objekty při ukončení programu, takže není třeba vytvořit kód pro výpis objektů v daném okamžiku.

Následující kód testuje porovnáním dvou států paměti nevracení paměti a vypíše všechny objekty v případě zjištění nevracení.

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 v závorkách na začátku Většina linek určit pořadí, ve kterém byly přiděleny objekty.Nedávno přidělené objekt má nejvyšší číslo a zobrazí se v horní části výpis stavu.

Chcete-li získat maximální množství informací z výpisu objektu, můžete přepsat Dump členskou funkci některého CObject-odvozený objekt, chcete-li upravit objekt s výpisem stavu paměti.

Můžete nastavit zarážku na přidělení určité paměti nastavením globální proměnnou _afxBreakAlloc na číslo uvedené ve složených závorkách.Je-li znovu spustit program ladicí program přerušit provádění při tomto přidělením.Potom můžete prohlédnout zásobník volání, chcete-li zjistit, jak váš program obdržel k tomuto bodu.

Běhová knihovna C má podobnou funkci, _CrtSetBreakAlloc, která slouží k rozdělení C run-time.

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifInterpretace paměti vypíše

Podívejte se na tento objekt dump 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ý tento výpis generován měl pouze dva explicitní rozdělení – jeden zásobník a druhý na haldě:

// 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 trvá tři argumenty, které jsou odkazy na char, který slouží k inicializaci CString proměnné členů.Ve výpisu stavu paměti naleznete CPerson objekt spolu s třemi nonobject bloky (3, 4 a 5).Tyto obsahovat znaky pro CString proměnné členů a nebudou odstraněny, když CPerson vyvolání destruktoru objektu.

Blok číslo 2 je CPerson samotného objektu.$51A4představuje adresa bloku a je následován obsah objektu, které byly výstupu CPerson::Dump při volání DumpAllObjectsSince.

Lze uhodnout, přidružené blok číslo 1 CString rámečku proměnné z důvodu jeho pořadové číslo a velikost, která odpovídá počtu znaků v rámci CString proměnné.Proměnné, které jsou přiděleny v rámci jsou navrácen automaticky, když rámeček nedostane mimo rozsah platnosti.

Proměnné rámce

Obecně by neměly starosti haldy objekty spojené s rámečku proměnné, protože jsou automaticky odebrána při proměnné rámce, které přesahují rozsah platnosti.Aby nepořádek ve své diagnostické výpisů stavu paměti by umístit volání na Checkpoint tak, aby byly mimo oblast působnosti rámce proměnné.Například umístíte oboru hranaté závorky kolem předchozího 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ávorkách oboru v místě výpisu 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 (jako například CPerson) a některé jsou nonobject rozdělení. "Nonobject přidělení"jsou přidělení pro objekty, které není odvozena z CObject nebo přidělení primitivní typy C, jako char, int, nebo dlouho.Pokud třídy CObject -odvozené třídy přidělí další místo, jako například pro vnitřní vyrovnávací paměti, ty objekty, které se zobrazí rozdělení objektu a nonobject.

Zabránění nevrácené paměti

Všimněte si z kódu výše, že blok paměti přidružené CString rámeček proměnná má automaticky odebrána a nezobrazuje jako nevracení paměti.Automatické navracení zpět přidružených oborů pravidel pečuje o většina nevracení paměti, které jsou přidružené k rámečku proměnné.

U objektů přiděleny na haldě modulu však musíte explicitně odstranit objekt, aby se zabránilo nevracení paměti.Vyčistit poslední nevracení paměti v předchozím příkladu, odstranit CPerson objekt přiděleny na haldě, 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

7sx52ww7.collapse_all(cs-cz,VS.110).gifVypíše úpravy objektu

Při odvození třídy z třídy CObject, můžete přepsat Dump členské funkce pro poskytnutí dalších informací, při použití DumpAllObjectsSince výpis objektů a okno výstup.

Dump Funkce zapíše textová reprezentace objektu členské proměnné Výpis kontextu (CDumpContext).Výpis kontextu je podobný datovému proudu vstupně-výstupní operace.Můžete použít operátor připojit (<<) k odesílání dat do CDumpContext.

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

Prohlášení o Dump funkce vypadá takto:

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

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

Protože objekt dumpingu smysl pouze při ladění aplikace, prohlášení o Dump je funkce bracketed s #ifdef _DEBUG / #endif bloku.

V následujícím příkladu Dump první volání funkce Dump funkce pro svou základní třídu.Poté zapíše stručný popis každé členské proměnné spolu s hodnotou členu diagnostické 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 moct výstup s výpisem stavu paměti.Ladicí verze knihovny MFC poskytuje předdefinované šablony, CDumpContext objekt s názvem afxDump , odešle výstup do ladicího programu.

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šení velikosti sestavení pro ladění MFC

Informace o ladění pro velké aplikace knihovny MFC může trvat až velké množství místa na disku.Chcete-li zmenšit velikost můžete použít jeden z těchto postupů:

  1. Sestavení knihovny MFC pomocí / Z7, /Zi, /ZI (informace o ladění formát) možnost, nikoli /Z7.Tyto možnosti sestavit soubor databáze (PDB) jednoho programu, který obsahuje informace o ladění pro celou knihovnu, snížení redundance a úspora místa.

  2. Sestavení knihovny MFC bez informace o ladění (žádný / Z7, /Zi, /ZI (informace o ladění formát) možnost).V tomto případě nedostatečné informace o ladění brání použití většiny zařízení debugger kódu knihovny MFC, ale protože knihoven MFC jsou již důkladně ladění, to nemusí být problém.

  3. Vytvoření aplikace s ladicími informacemi pro vybrané moduly pouze, jak je popsáno níže.

V tomto tématu

7sx52ww7.collapse_all(cs-cz,VS.110).gifVytvoření knihovny MFC aplikace s ladicími informacemi pro vybrané moduly

Vytváření vybrané moduly s ladění knihovny MFC umožňuje pomocí krokování a ladění zařízení v těchto modulech.Tento postup využívá obou Debug a Release režimy makefile Visual C++, což nutně změny popsané v následující kroky (a také potřeby provedení "znovu všechny"), pokud je požadována úplná verze sestavení.

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

  2. Z zobrazení přejděte na příkaz Stránky vlastností.

  3. Nejprve je třeba vytvořit nové konfigurace projektu.

    1. V <Project> Stránky vlastností dialogové okno, klepněte Správce konfigurace tlačítko.

    2. V dialogové okno Správce konfigurace, vyhledejte projekt v mřížce.V Konfigurace sloupec, vyberte < nový... >.

    3. V dialogové okno nové konfigurace projektu, zadejte název nové konfigurace, jako je například "Částečné ladění", Název konfigurace projektu pole.

    4. V Kopírovat nastavení z seznam, zvolte vydání.

    5. Klepněte na tlačítko OK zavřete Nové konfigurace projektudialogové okno.

    6. Zavřít Správce konfigurace dialogové okno.

  4. Nyní musíte nastavit možnosti pro celý projekt.

    1. V Stránky vlastností dialogovém okně vyberte v seznamu Vlastnosti konfigurace složku, vyberte Obecné kategorie.

    2. V tabulce nastavení projektu, rozbalte položku Výchozí nastavení projektu (je-li to nutné).

    3. Podle Výchozí nastavení projektu, najít Použití knihovny MFC.V pravém sloupci mřížky se zobrazí aktuální nastavení.Klepněte na aktuální nastavení a změňte ho na Použít knihovnu MFC ve statické knihovně.

    4. V levém podokně Stránky vlastnosti otevřete dialogové okno C/C++ složku a vyberte preprocesoru.V mřížce vlastnosti najít Preprocesoru a "NDEBUG" nahraďte "_DEBUG".

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

    6. Klepněte na tlačítko OK nové možnosti sestavení uložit a zavřít Stránky vlastností dialogové okno.

  5. Z sestavení přejděte na příkaz znovu.Odebere všechny informace o ladění v modulech, ale nemá vliv na knihovnu MFC.

  6. Nyní je třeba přidat informace o ladění zpět do vybrané moduly ve vaší aplikaci.Mějte na paměti, že můžete nastavit zarážky a provádět další funkce ladicí program pouze v modulech, které byly zkompilovány s ladicími informacemi.Pro každý projekt soubor, do kterého chcete zahrnout informace o ladění, proveďte následující kroky:

    1. V okně Průzkumník řešení otevřete Zdrojové soubory složka umístěna v projektu.

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

    3. Z zobrazení přejděte na příkaz Stránky vlastností.

    4. V Stránky vlastností dialogovém okně vyberte v seznamu Nastavení konfigurace složku, Otevřít C/C++ vyberte složku Obecné kategorie.

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

    6. Klepněte Debug Information Format nastavení a vyberte požadovanou možnost (obvykle /ZI) pro informace o ladění.

    7. Pokud používáte aplikaci průvodcem generované aplikací nebo mít předkompilována záhlaví, budete muset vypnout Předkompilovaná záhlaví nebo zkompilováním před ostatním modulům kompilace.V opačném případě obdržíte upozornění C4650 a chybová zpráva C2855.Předkompilovaná záhlaví můžete vypnout změnou Vytvoření/použití předkompilovaných hlaviček nastavení <Project> Vlastnosti dialogové okno (Vlastnosti konfigurace složky, C/C++ podsložky, Předkompilované hlavičky kategorie).

  7. Z sestavení přejděte na příkaz sestavení Chcete-li znovu vytvořit soubory projektu, které jsou zastaralé.

Jako alternativu 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ě propojení s ladění knihoven MFC, je nutné definovat _DEBUG příznak pro každý modul.Pokud chcete použít verzi knihovny MFC, je nutné definovat NDEBUG.Další informace o psaní externí makefiles najdete NMAKE odkaz.

V tomto tématu

Viz také

Další zdroje

Ladění aplikace Visual C++