Sdílet prostřednictvím


Ladění CRT haldy

Toto téma obsahuje podrobný pohled halda ladění CRT.

V tomto tématu

Správa paměti a halda ladění

Typy bloků na haldě ladění

Funkce ladění haldy

Pomocí ladění haldy

nové, odstranit a _CLIENT_BLOCKs v v jazyce C++ ladění haldy

Funkce vykazování stavu haldy

Sledování žádostí o přidělení haldy

Správa paměti a halda ladění

Dva z nejběžnějších a intractable problémy, které se vyskytnou programátoři přepisování konec přidělené vyrovnávací paměti a paměť nevrací (neúspěšný pokus uvolnit přidělení poté, co již nejsou zapotřebí).Halda ladění poskytuje výkonné nástroje pro řešení problémů s přidělením paměti tohoto druhu.

Ladicí verze haldy funkcí volání standardní nebo základní verze používané ve verzi sestavení.Požadujete-li blok paměti, správce hald ladění vyhradí ze základní haldy poněkud větší blok paměti, než je požadováno a vrací ukazatel na své části bloku.Předpokládejme například, že aplikace obsahuje volání: malloc( 10 ).Ve vydané verzi MALLOC by volání rutiny přidělení haldy základní žádosti o přidělení 10 bajtů.V sestavení ladění, ale malloc by _malloc_dbg, který poté zavolat rutinu přidělení haldy základní žádosti o přidělení 10 bajtů plus přibližně 36 bajtů paměti.Všechny výsledné bloky paměti haldy pro ladění jsou spojeny v jediné propojeného seznamu seřazeny podle kdy byly přiděleny.

Další paměti přidělené haldy rutin ladění slouží pro informace o účetnictví, pro ukazatele, že odkaz ladění paměti bloky dohromady a pro malé vyrovnávací paměti na obou stranách data zachytit přepíše přidělené oblasti.

Struktura hlavičky blok slouží k ukládání informací účetnictví halda ladění je v současné době takto deklarované v DBGINT.H souboru hlaviček:

typedef struct _CrtMemBlockHeader
{
// Pointer to the block allocated just before this one:
    struct _CrtMemBlockHeader *pBlockHeaderNext;
// Pointer to the block allocated just after this one:
    struct _CrtMemBlockHeader *pBlockHeaderPrev;
    char *szFileName;    // File name
    int nLine;           // Line number
    size_t nDataSize;    // Size of user block
    int nBlockUse;       // Type of block
    long lRequest;       // Allocation number
// Buffer just before (lower than) the user's memory:
    unsigned char gap[nNoMansLandSize];
} _CrtMemBlockHeader;

/* In an actual memory block in the debug heap,
 * this structure is followed by:
 *   unsigned char data[nDataSize];
 *   unsigned char anotherGap[nNoMansLandSize];
 */

NoMansLand Vyrovnávacích pamětí na obou stranách uživatelské datové oblasti bloku jsou nyní 4 bajty, velikost a jsou vyplněny známé bajt hodnota použitá rutinami halda ladění ověřit, že nebyly limity bloku paměti uživatele přepsán.Halda ladění také vyplní nové bloky paměti se známou hodnotu.Pokud se rozhodnete zachovat v propojeném seznamu do haldy uvolněné bloky, jak je popsáno níže, jsou tyto uvolněné bloky také vyplněny známé hodnoty.Skutečné bajt hodnoty použité v současné době jsou následující:

  • NoMansLand (0xFD)
    Vyrovnávací paměti "NoMansLand" na obou stranách paměti používané aplikace jsou vyplněny právě 0xFD.

  • Uvolněné bloky (0xDD)
    Uvolněné bloky, které jsou uchovávány v nepoužívané halda ladění společnosti propojené seznam, kdy _CRTDBG_DELAY_FREE_MEM_DF je nastaven příznak, jsou nyní vyplněny 0xDD.

  • Nové objekty (0xCD)
    Nové objekty jsou vyplněny 0xCD, pokud jsou přiděleny.

    V tomto tématu

Typy bloků na haldě ladění

Každý blok paměti haldy pro ladění je přiřazen jeden z pěti typů přidělení.Tyto typy jsou sledovány a jinak hlášeny pro účely detekce nevracení paměti a vykazování stavu.Můžete určit typ bloku tak, jako je například pomocí přímého volání k jedné z funkcí přidělení haldy ladění _malloc_dbg.Pět typů bloků paměti haldy pro ladění (v nBlockUse člen _CrtMemBlockHeader struktury) jsou následující:

  • _NORMAL_BLOCK
    Volání malloc nebo calloc vytvoří normální blok.Pokud máte v úmyslu používat pouze normální bloky a nepotřebujete pro klienta bloky, může být vhodné definovat _CRTDBG_MAP_ALLOC, což způsobí, že všechna přidělení haldy volá namapovat na jejich ekvivalenty ladění v sestavení ladění.To vám umožní soubor název a řádek číselné informace o každé volání přidělení uložena v odpovídající nadpis bloku.

  • _CRT_BLOCK
    Bloky paměti přidělené interně mnoho funkcí knihovny run-time jsou označeny jako CRT bloky tak mohou být zpracovány odděleně.V důsledku toho se nevrací zjišťování a další operace nemusí být ovlivněna jejich.Přidělení nikdy musí přidělit, přerozdělit nebo bez jakéhokoliv bloku typu CRT.

  • _CLIENT_BLOCK
    Aplikace můžete sledovat zvláštní dané skupiny úvěrů pro účely ladění tak, jako tento typ bloku paměti pomocí explicitní volání funkcí ladění haldy.Přidělí všechny knihovny MFC, například CObjects jako klient bloky; ostatní aplikace mohou být různé paměťové objekty v blocích klienta.Podtypy klienta bloky lze zadat také pro větší rozlišovací schopnost sledování.Určit podtypy klienta bloků, posun číslo po 16 bitů a OR s _CLIENT_BLOCK.Příklad:

    #define MYSUBTYPE 4
    freedbg(pbData, _CLIENT_BLOCK|(MYSUBTYPE<<16));
    

    Funkce klient dodávaný háčkem dumpingu objekty uložené v blocích klienta lze nainstalovat pomocí _CrtSetDumpClienta pak zavolá vždy, když klient blok vypsána funkce ladění.Také _CrtDoForAllClientObjects lze použít k volání dané funkce poskytované aplikací pro každého klienta bloku haldy pro ladění.

  • _FREE_BLOCK
    Za normálních okolností bloky, které jsou uvolněny budou odebrány ze seznamu.Chcete-li zkontrolovat, že uvolněné paměti není stále byla zapsána do nebo simulovat podmínky nedostatku paměti, budete pravděpodobně chtít zachovat uvolněné bloky v propojeném seznamu označena jako svobodného a hodnotu bajtu známé (nyní 0xDD).

  • _IGNORE_BLOCK
    Je možné vypnout ladění operací haldy pro určitý časový úsek.Během této doby bloky paměti jsou uloženy v seznamu, ale označeny jako ignorovat bloky.

Chcete-li určit typ a podtyp daného bloku, použijte funkci _CrtReportBlockType a _BLOCK_TYPE a _BLOCK_SUBTYPE.Makra jsou definovány takto (v crtdbg.h):

#define _BLOCK_TYPE(block)          (block & 0xFFFF)
#define _BLOCK_SUBTYPE(block)       (block >> 16 & 0xFFFF)

V tomto tématu

Funkce ladění haldy

Mnoho funkcí ladění haldy musí přistoupit z vašeho kódu.V následující části jsou popsány některé funkce a jejich použití.

  • _CrtCheckMemory
    Můžete použít volání _CrtCheckMemory, například pro kontrolu integrity do haldy v libovolném bodě.Tato funkce zkontroluje každý blok paměti haldy, ověří, zda jsou informace záhlaví bloku paměti platné a potvrzuje, že nebyly provedeny žádné úpravy vyrovnávacích pamětí.

  • _CrtSetDbgFlag
    Můžete určit, jak je halda ladění uchovává informace o přidělení pomocí interní příznak, _crtDbgFlag, které lze číst a nastavit pomocí _CrtSetDbgFlag funkce.Změníte-li tento příznak, dáte pokyn halda ladění kontrolu nevracení paměti při ukončení programu a hlásit případné úniky, které jsou zjištěny.Podobně můžete určit, že uvolněné paměti bloky nesmí být odebráno z propojený seznam pro simulaci paměti situacích.Při kontrole haldy tyto uvolněné bloky byly kontrolovány v plné výši, aby bylo zajištěno, aby nebyl narušen.

    _CrtDbgFlag příznak obsahuje následující pole bit:

    Bitové pole

    Výchozí

    hodnota

    Description

    _CRTDBG_ALLOC_MEM_DF

    Na

    Zapne ladění přidělení.Když tento bit vypnutý, zůstávají přidělení zřetězeno, ale jejich typ bloku je _IGNORE_BLOCK.

    _CRTDBG_DELAY_FREE_MEM_DF

    Vypnutí

    Zabrání skutečně Uvolňovaná, stejně jako pro simulace nedostatku paměti paměti.Pokud je tento bit, jsou uchovávány v propojeného seznamu ladění haldy uvolněné bloky, ale jsou označeny jako _FREE_BLOCK a speciální byte hodnotu.

    _CRTDBG_CHECK_ALWAYS_DF

    Vypnutí

    Způsobí, že _CrtCheckMemory Chcete-li volat v každé přidělování a navracení zpět.Zpomalí spouštění, ale rychle zachytí chyby.

    _CRTDBG_CHECK_CRT_DF

    Vypnutí

    Způsobí, že bloky, které jsou označeny jako typ _CRT_BLOCK mají být zahrnuty do detekce nevrácení a rozdíl stavu operace.Při vypnutí je tento bit paměti používá interně knihovna run-time ignorovány během těchto operací.

    _CRTDBG_LEAK_CHECK_DF

    Vypnutí

    Způsobuje nevracení paměti kontroly mají být provedeny při ukončení programu prostřednictvím volání _CrtDumpMemoryLeaks.Zpráva o chybě je generována, pokud aplikace se nepodařilo uvolnit paměť, která je přidělena.

V tomto tématu

Pomocí ladění haldy

Všechna volání funkce haldy malloc, free, calloc, realloc, new, a delete řešení pro ladicí verze těchto funkcí, které působí v ladění haldy.Při uvolnění paměti bloku halda ladění automaticky kontroluje integritu vyrovnávacích pamětí na obou stranách přidělené oblasti a zprávy o chybách v případě přepsání došlo.

Chcete-li použít ladění haldy

  • Propojte sestavení ladění aplikace s ladicí verzi běhové knihovny C.

Chcete-li změnit jedno nebo více polí bit _crtDbgFlag a vytvořte nový stav příznaku

  1. Volání _CrtSetDbgFlag se newFlag parametr nastaven na _CRTDBG_REPORT_FLAG (získat aktuální _crtDbgFlag státu) a vrácená hodnota uloží do dočasné proměnné.

  2. Zapněte všechny bity podle OR- ing (bitového | symbol) dočasnou proměnnou s odpovídající bitovou masku (představovaný v kódu aplikace manifestu konstanty).

  3. Vypnout ostatní bity podle AND- ing (bitový operátor & symbol) proměnné s NOT (bitový operátor ~ symbol) z příslušné bitovou masku.

  4. Volání _CrtSetDbgFlag se newFlag parametr nastaven na hodnotu uloženou v dočasnou proměnnou k vytvoření nového stavu pro _crtDbgFlag.

Například následující řádky kódu zapnout automatické zjištění a vypnutí kontroly bloků typu _CRT_BLOCK:

// Get current flag
int tmpFlag = _CrtSetDbgFlag( _CRTDBG_REPORT_FLAG );

// Turn on leak-checking bit.
tmpFlag |= _CRTDBG_LEAK_CHECK_DF;

// Turn off CRT block checking bit.
tmpFlag &= ~_CRTDBG_CHECK_CRT_DF;

// Set flag to the new value.
_CrtSetDbgFlag( tmpFlag );

nové, odstranit a _CLIENT_BLOCKs v v jazyce C++ ladění haldy

Ladicí verze knihovny běhu jazyka C obsahují ladicí verze v jazyce C++ new a delete operátory.Použijete-li _CLIENT_BLOCK typ rozdělení, musíte zavolat ladicí verzi new přímo operátor nebo vytvoření makra, které nahrazují new operátor v režimu ladění, jak je znázorněno v následujícím příkladu:

/* MyDbgNew.h
 Defines global operator new to allocate from
 client blocks
*/

#ifdef _DEBUG
   #define DEBUG_CLIENTBLOCK   new( _CLIENT_BLOCK, __FILE__, __LINE__)
#else
   #define DEBUG_CLIENTBLOCK
#endif // _DEBUG


/* MyApp.cpp
        Use a default workspace for a Console Application to
 *      build a Debug version of this code
*/

#include "crtdbg.h"
#include "mydbgnew.h"

#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif

int main( )   {
    char *p1;
    p1 =  new char[40];
    _CrtMemDumpAllObjectsSince( NULL );
}

Ladicí verze delete operátor pracuje s blokování všech typů a nevyžaduje žádné změny v programu, při kompilaci vydané verze.

Funkce vykazování stavu haldy

_CrtMemState

K zachycení souhrnný snímek stavu haldy v daném čase, pomocí _CrtMemState struktury definované v CRTDBG.H:

typedef struct _CrtMemState
{
    // Pointer to the most recently allocated block:
    struct _CrtMemBlockHeader * pBlockHeader;
    // A counter for each of the 5 types of block:
    size_t lCounts[_MAX_BLOCKS];
    // Total bytes allocated in each block type:
    size_t lSizes[_MAX_BLOCKS];
    // The most bytes allocated at a time up to now:
    size_t lHighWaterCount;
    // The total bytes allocated at present:
    size_t lTotalCount;
} _CrtMemState;

Tato struktura uloží ukazatel na první blok (nejčastěji přidělené nedávno) v ladění haldy propojený seznam.Potom ve dvou maticích zaznamenává počet jednotlivých typů paměti blokovat (_NORMAL_BLOCK, _CLIENT_BLOCK, _FREE_BLOCK, a tak dále) jsou uvedeny v seznamu a počet bytů alokovaných v jednotlivých typů bloků.Nakonec zaznamená nejvyšší počet bytů alokovaných v haldě jako celek až k danému bodu a počet bajtů, které jsou aktuálně přiděleny.

Ostatní funkce vykazování CRT

Následující funkce sestav stav a obsah haldy a využít tyto informace pomáhají zjišťovat nevrácenou paměť a další problémy.

Function

Description

_CrtMemCheckpoint

Uloží snímek haldy v _CrtMemState struktury poskytnutou aplikací.

_CrtMemDifference

Porovná dvě paměti státních struktur, uloží rozdíl mezi nimi ve struktuře třetí stát a vrátí hodnotu PRAVDA, pokud se liší ve dvou státech.

_CrtMemDumpStatistics

Vypíše informace dané _CrtMemState struktury.Struktura může obsahovat snímek stavu ladění haldy v daném okamžiku nebo rozdíl mezi dva snímky.

_CrtMemDumpAllObjectsSince

Vypíše informace o všech objektů, které jsou přiděleny, protože daný snímek byl pořízen v haldě nebo od začátku spuštění.Pokaždé, když ho vypíše _CLIENT_BLOCK blok, volá funkci hák, poskytnutou aplikací, je-li jeden byl nainstalován pomocí _CrtSetDumpClient.

_CrtDumpMemoryLeaks

Určuje, zda paměť nevrací došlo od začátku provádění programu a pokud ano, vypíše všechny přidělené objekty.Pokaždé, když _CrtDumpMemoryLeaks vypíše _CLIENT_BLOCK blok, volá funkci hák, poskytnutou aplikací, je-li jeden byl nainstalován pomocí _CrtSetDumpClient.

V tomto tématu

Sledování žádostí o přidělení haldy

Ačkoli přesným rozpoznáním číslo zdrojového souboru název a řádek, na které assert nebo přídavné makro provede je často velmi užitečné při hledání příčin potíží, není stejný jako pravděpodobné, že budou splněny funkcí přidělení haldy.Zatímco makra lze vložit na mnoho vhodných místech v logické stromové struktuře aplikace, přidělení často schovaný ve zvláštní rutina, která je volána z mnoha různých místech v mnoha různých časech.Otázkou je obvykle nedošlo chybné přidělení jaký řádek kódu, ale spíše níž je jedna z tisíců přidělení provedené tohoto řádku kódu byla chybná a proč.

Jedinečná požadavek na přidělení čísla a _crtBreakAlloc

Nejjednodušší způsob, jak identifikovat volání přidělení haldy specifické, které dostalo chybné je využít číslo žádosti o přidělení jedinečné u každého bloku haldy pro ladění.Je-li informace o blok je vykazován jednu z funkcí s výpisem stavu paměti, je toto číslo žádosti o přidělení uzavřeny ve složených závorkách (například {36}).

Jakmile znáte číslo žádosti o přidělení nesprávně přiděleného bloku, můžete předat toto číslo na _CrtSetBreakAlloc Chcete-li vytvořit zarážku.Spuštění přerušíte těsně před přidělením bloku a mohou navrátit do zjistit, jaká byla zahájena rutina byla odpovědná za chybné volání.Chcete-li se vyhnout nutnosti znovu kompilovat, můžete provést totéž v ladicím programu nastavením _crtBreakAlloc na číslo žádosti o přidělení se zajímáte.

Vytváření ladicí verze tak rutinní přidělení

Poněkud složitější přístupem je vytvoření ladicí verze vlastní rutiny přidělení, srovnatelné _dbg verze funkcí přidělení haldy.Potom můžete předat zdrojového souboru a řádek argumentů prostřednictvím podkladové rutin přidělení haldy a okamžitě bude moci zjistit, odkud pochází chybné přidělení.

Například předpokládejme, že aplikace obsahuje běžně používané rutinu, která je podobná následující:

int addNewRecord(struct RecStruct * prevRecord,
                 int recType, int recAccess)
{
    // ...code omitted through actual allocation... 
    if ((newRec = malloc(recSize)) == NULL)
    // ... rest of routine omitted too ... 
}

V hlavičkovém souboru můžete přidat kód jako následující:

#ifdef _DEBUG
#define  addNewRecord(p, t, a) \
            addNewRecord(p, t, a, __FILE__, __LINE__)
#endif

Dále lze změnit rozdělení do vaší běžné vytvoření záznamu takto:

int addNewRecord(struct RecStruct *prevRecord,
                int recType, int recAccess
#ifdef _DEBUG
               , const char *srcFile, int srcLine
#endif
    )
{
    /* ... code omitted through actual allocation ... */
    if ((newRec = _malloc_dbg(recSize, _NORMAL_BLOCK,
            srcFile, scrLine)) == NULL)
    /* ... rest of routine omitted too ... */
}

Nyní číslo zdrojového souboru název a řádek, kde addNewRecord byla volána budou uloženy v každém výsledné bloku přidělení haldy pro ladění a budou uvedeny v případě, že tento blok je zkontrolován.

V tomto tématu

Viz také

Další zdroje

Ladění nativního kódu

Techniky ladění CRT