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.
Sledová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
Povolení 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
Pořizování snímků paměti
Vytvoření CMemoryState objekt a volání CMemoryState::Checkpoint členské funkce.Tím se vytvoří první snímek paměti.
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.
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
Zobrazení 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
Vypíš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
Interpretace 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
Vypíš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ů:
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.
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.
Vytvoření aplikace s ladicími informacemi pro vybrané moduly pouze, jak je popsáno níže.
V tomto tématu
Vytvoř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í.
V Průzkumníku řešení vyberte projekt.
Z zobrazení přejděte na příkaz Stránky vlastností.
Nejprve je třeba vytvořit nové konfigurace projektu.
V <Project> Stránky vlastností dialogové okno, klepněte Správce konfigurace tlačítko.
V dialogové okno Správce konfigurace, vyhledejte projekt v mřížce.V Konfigurace sloupec, vyberte < nový... >.
V dialogové okno nové konfigurace projektu, zadejte název nové konfigurace, jako je například "Částečné ladění", Název konfigurace projektu pole.
V Kopírovat nastavení z seznam, zvolte vydání.
Klepněte na tlačítko OK zavřete Nové konfigurace projektudialogové okno.
Zavřít Správce konfigurace dialogové okno.
Nyní musíte nastavit možnosti pro celý projekt.
V Stránky vlastností dialogovém okně vyberte v seznamu Vlastnosti konfigurace složku, vyberte Obecné kategorie.
V tabulce nastavení projektu, rozbalte položku Výchozí nastavení projektu (je-li to nutné).
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ě.
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".
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."
Klepněte na tlačítko OK nové možnosti sestavení uložit a zavřít Stránky vlastností dialogové okno.
Z sestavení přejděte na příkaz znovu.Odebere všechny informace o ladění v modulech, ale nemá vliv na knihovnu MFC.
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:
V okně Průzkumník řešení otevřete Zdrojové soubory složka umístěna v projektu.
Vyberte soubor, který chcete nastavit informace o ladění pro.
Z zobrazení přejděte na příkaz Stránky vlastností.
V Stránky vlastností dialogovém okně vyberte v seznamu Nastavení konfigurace složku, Otevřít C/C++ vyberte složku Obecné kategorie.
V mřížce vlastnosti najít Debug Information Format.
Klepněte Debug Information Format nastavení a vyberte požadovanou možnost (obvykle /ZI) pro informace o ladění.
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).
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