Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
CRT-felsöknings heap och relaterade funktioner ger många sätt att spåra och felsöka problem med minneshantering i koden. Du kan använda den för att hitta buffertöverskridningar och för att spåra och rapportera minnesallokeringar och minnestillstånd. Den har också stöd för att skapa egna felsökningsallokeringsfunktioner för dina unika appbehov.
Hitta buffertöverskridningar med felsöknings-heap
Två av de vanligaste och svårlösta problem som programmerare stöter på skriver över slutet på en allokerad buffert och minnesläckor (misslyckas med att frigöra allokeringar när de inte längre behövs). Felsöknings-heapen innehåller kraftfulla verktyg för att lösa problem med minnesallokering av den här typen.
Felsökningsversionerna av heapfunktionerna anropar standardversionerna eller basversionerna som används i Versionsversioner. När du begär ett minnesblock allokerar felsökningshanteraren från bashögen ett något större minnesblock än du begärde och returnerar en pekare till din del av blocket. Anta till exempel att programmet innehåller anropet: malloc( 10 ). I en Versionsversion malloc anropar du den grundläggande heap-allokeringsrutinen och begär en allokering på 10 byte. I en felsökningsversion anropar mallocdock _malloc_dbg , som sedan anropar den grundläggande heapallokeringsrutinen och begär en allokering på 10 byte plus cirka 36 byte extra minne. Alla resulterande minnesblock i felsöknings-heapen är anslutna i en enda länkad lista, ordnade enligt när de allokerades.
Det extra minne som allokeras av felsöknings-heaprutinerna används för bokföringsinformation. Den har pekare som länkar samman felsökningsminnesblock och små buffertar på båda sidor av dina data för att fånga överskrivningar av den allokerade regionen.
För närvarande deklareras blockhuvudstrukturen som används för att lagra felsöknings heapens bokföringsinformation i <crtdbg.h> rubriken och definieras i <debug_heap.cpp> CRT-källfilen. Konceptuellt liknar den den här strukturen:
typedef struct _CrtMemBlockHeader
{
// Pointer to the block allocated just before this one:
_CrtMemBlockHeader* _block_header_next;
// Pointer to the block allocated just after this one:
_CrtMemBlockHeader* _block_header_prev;
char const* _file_name;
int _line_number;
int _block_use; // Type of block
size_t _data_size; // Size of user block
long _request_number; // Allocation number
// Buffer just before (lower than) the user's memory:
unsigned char _gap[no_mans_land_size];
// Followed by:
// unsigned char _data[_data_size];
// unsigned char _another_gap[no_mans_land_size];
} _CrtMemBlockHeader;
Buffertarna no_mans_land på vardera sidan av användardataområdet i blocket är för närvarande 4 byte i storlek och är fyllda med ett känt bytevärde som används av felsöknings-heaprutinerna för att verifiera att gränserna för användarens minnesblock inte har skrivits över. Felsöknings-heapen fyller också nya minnesblock med ett känt värde. Om du väljer att behålla frigjorda block i heapens länkade lista fylls även dessa frigjorda block med ett känt värde. För närvarande används de faktiska bytevärdena på följande sätt:
| Kod | Beskrivning |
|---|---|
no_mans_land (0xFD) |
Buffertarna "no_mans_land" på båda sidor av minnet som används av ett program är för närvarande fyllda med 0xFD. |
| Frigjorda block (0xDD) | De frigjorda blocken som inte används i felsöknings heapens länkade lista när _CRTDBG_DELAY_FREE_MEM_DF flaggan har angetts är för närvarande fylld med 0xDD. |
| Nya objekt (0xCD) | Nya objekt fylls med 0xCD när de allokeras. |
Typer av block på felsöknings-heapen
Varje minnesblock i felsöknings heapen tilldelas till en av fem allokeringstyper. Dessa typer spåras och rapporteras på olika sätt i syfte att identifiera läckor och rapportera tillstånd. Du kan ange ett blocktyp genom att allokera den med hjälp av ett direktanrop till någon av funktionerna för felsökning av heapallokering, till exempel _malloc_dbg. De fem typerna av minnesblock i felsöknings-heapen nBlockUse (som anges i strukturens medlem _CrtMemBlockHeader ) är följande:
_NORMAL_BLOCK
Ett anrop till malloc eller calloc skapar ett normalblock. Om du endast tänker använda normalblock och inte behöver klientblock kanske du vill definiera _CRTDBG_MAP_ALLOC.
_CRTDBG_MAP_ALLOC gör att alla heap-allokeringsanrop mappas till deras felsökningsekvivalenter i felsökningsversioner. Det tillåter lagring av filnamn och radnummerinformation om varje allokeringsanrop i motsvarande blockrubrik.
_CRT_BLOCK
Minnesblocken som allokeras internt av många körningsbiblioteksfunktioner markeras som CRT-block så att de kan hanteras separat. Därför kan läckageidentifiering och andra åtgärder förbli opåverkade av dem. En allokering får aldrig allokera, omallokera eller frigöra något block av CRT-typ.
_CLIENT_BLOCK
Ett program kan hålla särskild koll på en viss grupp med allokeringar i felsökningssyfte genom att allokera dem som den här typen av minnesblock med hjälp av explicita anrop till felsöknings-heapfunktionerna. MFC allokerar till exempel alla CObject objekt som klientblock. Andra program kan behålla olika minnesobjekt i klientblock. Undertyper av klientblock kan också anges för större spårningskornighet. Om du vill ange undertyper av klientblock flyttar du antalet kvar med 16 bitar och OR det med _CLIENT_BLOCK. Till exempel:
#define MYSUBTYPE 4
freedbg(pbData, _CLIENT_BLOCK|(MYSUBTYPE<<16));
En hook-funktion som tillhandahålls av klienten för dumpning av objekt som lagras i klientblock kan installeras med , _CrtSetDumpClientoch anropas sedan när ett klientblock dumpas av en felsökningsfunktion.
_CrtDoForAllClientObjects Kan också användas för att anropa en viss funktion som tillhandahålls av programmet för varje klientblock i felsöknings-heapen.
_FREE_BLOCK
Normalt tas block som frigörs bort från listan. Om du vill kontrollera att frigjort minne inte skrivs till eller för att simulera låg minnesanvändning kan du behålla frigjorda block i den länkade listan, markerad som Kostnadsfri och fylld med ett känt bytevärde (för närvarande 0xDD).
_IGNORE_BLOCK
Det går att inaktivera felsöknings-heapåtgärderna under ett visst intervall. Under den här tiden sparas minnesblock i listan, men markeras som Ignorera block.
Om du vill fastställa typen och undertypen för ett visst block använder du funktionen _CrtReportBlockType och makrona _BLOCK_TYPE och _BLOCK_SUBTYPE. Makrona definieras på <crtdbg.h> följande sätt:
#define _BLOCK_TYPE(block) (block & 0xFFFF)
#define _BLOCK_SUBTYPE(block) (block >> 16 & 0xFFFF)
Kontrollera heapintegritet och minnesläckor
Många av funktionerna i felsökningshögen måste nås inifrån koden. I följande avsnitt beskrivs några av funktionerna och hur du använder dem.
_CrtCheckMemory
Du kan använda ett anrop till till _CrtCheckMemoryexempel för att kontrollera heapens integritet när som helst. Den här funktionen inspekterar varje minnesblock i heapen. Den verifierar att minnesblockets rubrikinformation är giltig och bekräftar att buffertarna inte har ändrats.
_CrtSetDbgFlag
Du kan styra hur felsöknings-heapen håller reda på allokeringar med hjälp av en intern flagga, _crtDbgFlag, som kan läsas och ställas in med hjälp av _CrtSetDbgFlag funktionen. Genom att ändra den här flaggan kan du instruera felsöknings-heapen att söka efter minnesläckor när programmet avslutas och rapportera eventuella läckor som identifieras. På samma sätt kan du be heapen att lämna frigjorda minnesblock i den länkade listan för att simulera situationer med lågt minne. När heapen kontrolleras inspekteras dessa frigjorda block i sin helhet för att säkerställa att de inte har störts.
Flaggan _crtDbgFlag innehåller följande bitfält:
| Bitfält | Standardvärde | Beskrivning |
|---|---|---|
_CRTDBG_ALLOC_MEM_DF |
På | Aktiverar felsökningsallokering. När den här biten är inaktiverad förblir allokeringarna sammanlänkade, men deras blocktyp är _IGNORE_BLOCK. |
_CRTDBG_DELAY_FREE_MEM_DF |
Av | Förhindrar att minnet faktiskt frigörs, precis som för att simulera lågminnesförhållanden. När den här biten är på sparas frigjorda block i felsöknings heapens länkade lista men markeras som _FREE_BLOCK och fylls med ett särskilt bytevärde. |
_CRTDBG_CHECK_ALWAYS_DF |
Av | Orsaker _CrtCheckMemory som ska anropas vid varje allokering och frigöring. Körningen går långsammare, men den fångar upp fel snabbt. |
_CRTDBG_CHECK_CRT_DF |
Av | Orsakar block som markerats som typ _CRT_BLOCK som ska ingå i åtgärder för läckageidentifiering och tillståndsskillnad. När den här biten är avstängd ignoreras det minne som används internt av körningsbiblioteket under sådana åtgärder. |
_CRTDBG_LEAK_CHECK_DF |
Av | Gör att läckagekontroll utförs vid programavslut via ett anrop till _CrtDumpMemoryLeaks. En felrapport genereras om programmet inte har lyckats frigöra allt minne som det allokerade. |
Konfigurera felsöknings-heapen
Alla anrop till heap-funktioner som malloc, free, calloc, realloc, newoch delete matcha för att felsöka versioner av de funktioner som fungerar i felsöknings-heapen. När du frigör ett minnesblock kontrollerar felsöknings-heapen automatiskt integriteten för buffertarna på båda sidor av det allokerade området och utfärdar en felrapport om överskrivning har inträffat.
Så här använder du felsöknings-heapen
Länka felsökningsversionen av ditt program med en felsökningsversion av C-körningsbiblioteket.
Ändra ett eller flera _crtDbgFlag bitfält och skapa ett nytt tillstånd för flaggan
Anropa
_CrtSetDbgFlagmed parametern inställdnewFlagpå_CRTDBG_REPORT_FLAG(för att hämta aktuellt_crtDbgFlagtillstånd) och lagra det returnerade värdet i en tillfällig variabel.Aktivera eventuella bitar med hjälp av en bitvis
|operator ("eller") på den tillfälliga variabeln med motsvarande bitmasker (representeras i programkoden av manifestkonstanter).Inaktivera de andra bitarna med hjälp av en bitvis
&operator ("och") på variabeln med en bitvis~operator ("inte" eller komplement) för lämpliga bitmasker.Anropa
_CrtSetDbgFlagmed parameternnewFlaginställd på värdet som lagras i den tillfälliga variabeln för att skapa det nya tillståndet för_crtDbgFlag.Följande kodrader aktiverar till exempel automatisk läckageidentifiering och inaktiverar kontroller av block av typen
_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 );
new, deleteoch _CLIENT_BLOCK allokeringar i felsöknings-heapen C++
Felsökningsversionerna av C-körningsbiblioteket innehåller felsökningsversioner av C++ new och delete operatorer. Om du använder _CLIENT_BLOCK allokeringstypen måste du anropa felsökningsversionen av operatorn new direkt eller skapa makron som ersätter operatorn new i felsökningsläge, enligt följande exempel:
/* 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 );
}
Operatörens delete felsökningsversion fungerar med alla blocktyper och kräver inga ändringar i programmet när du kompilerar en versionsversion.
Rapporteringsfunktioner för heaptillstånd
Om du vill samla in en sammanfattningsögonblicksbild av heapens tillstånd vid en viss tidpunkt använder du strukturen _CrtMemState som definieras i <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;
Den här strukturen sparar en pekare till det första (senast allokerade) blocket i felsöknings heapens länkade lista. I två matriser registrerar den sedan hur många av varje typ av minnesblock (_NORMAL_BLOCK, , _CLIENT_BLOCK_FREE_BLOCKoch så vidare) som finns i listan och antalet byte som allokeras i varje typ av block. Slutligen registrerar den det högsta antalet byte som allokerats i heapen som helhet fram till den punkten och antalet byte som för närvarande allokeras.
Andra CRT-rapporteringsfunktioner
Följande funktioner rapporterar heapens tillstånd och innehåll och använder informationen för att identifiera minnesläckor och andra problem.
| Funktion | Beskrivning |
|---|---|
_CrtMemCheckpoint |
Sparar en ögonblicksbild av heapen i en _CrtMemState struktur som tillhandahålls av programmet. |
_CrtMemDifference |
Jämför två minnestillståndsstrukturer, sparar skillnaden mellan dem i en tredje tillståndsstruktur och returnerar TRUE om de två tillstånden skiljer sig åt. |
_CrtMemDumpStatistics |
Dumpar en viss _CrtMemState struktur. Strukturen kan innehålla en ögonblicksbild av tillståndet för felsöknings heapen vid en viss tidpunkt eller skillnaden mellan två ögonblicksbilder. |
_CrtMemDumpAllObjectsSince |
Dumpar information om alla objekt som allokerats sedan en viss ögonblicksbild togs av heapen eller från körningens början. Varje gång det dumpar ett _CLIENT_BLOCK block anropas en hook-funktion som tillhandahålls av programmet, om en har installerats med ._CrtSetDumpClient |
_CrtDumpMemoryLeaks |
Avgör om några minnesläckor har inträffat sedan programkörningen startade och i så fall dumpar alla allokerade objekt. Varje gång _CrtDumpMemoryLeaks ett _CLIENT_BLOCK block dumpas anropas en hook-funktion som tillhandahålls av programmet, om en har installerats med ._CrtSetDumpClient |
Spåra heapallokeringsbegäranden
Att känna till källfilens namn och radnummer för ett kontroll- eller rapporteringsmakron är ofta användbart för att hitta orsaken till ett problem. Detsamma gäller förmodligen inte för heapallokeringsfunktioner. Du kan infoga makron på många lämpliga punkter i ett programs logikträd, men en allokering är ofta begravd i en funktion som anropas från många olika platser vid många olika tidpunkter. Frågan är inte vilken kodrad som gjorde en felaktig allokering. I stället är det vilken av de tusentals allokeringar som gjorts av den kodraden var dålig och varför.
Unika nummer för allokeringsbegäran och _crtBreakAlloc
Det finns ett enkelt sätt att identifiera det specifika heapallokeringsanropet som gick dåligt. Den drar nytta av det unika allokeringsbegärandenumret som är associerat med varje block i felsöknings-heapen. När information om ett block rapporteras av en av dumpfunktionerna omges det här allokeringsbegärandenumret i klammerparenteser. Till exempel {36}.
När du känner till allokeringsbegärandenumret för ett felaktigt allokerat block kan du skicka det här numret till _CrtSetBreakAlloc för att skapa en brytpunkt. Körningen avbryts precis innan blocket allokeras och du kan backa för att avgöra vilken rutin som var ansvarig för det felaktiga anropet. För att undvika omkompilering kan du göra samma sak i felsökningsprogrammet genom att ange _crtBreakAlloc det nummer för allokeringsbegäran som du är intresserad av.
Skapa felsökningsversioner av dina allokeringsrutiner
En mer komplex metod är att skapa felsökningsversioner av dina egna allokeringsrutiner, jämförbara med versionerna _dbg av heap-allokeringsfunktionerna. Du kan sedan skicka källfils- och radnummerargument till de underliggande heapallokeringsrutinerna, och du kommer omedelbart att kunna se var en felaktig allokering har sitt ursprung.
Anta till exempel att ditt program innehåller en vanlig rutin som liknar följande exempel:
int addNewRecord(struct RecStruct * prevRecord,
int recType, int recAccess)
{
// ...code omitted through actual allocation...
if ((newRec = malloc(recSize)) == NULL)
// ... rest of routine omitted too ...
}
I en rubrikfil kan du lägga till kod, till exempel följande exempel:
#ifdef _DEBUG
#define addNewRecord(p, t, a) \
addNewRecord(p, t, a, __FILE__, __LINE__)
#endif
Därefter kan du ändra allokeringen i din postskapanderutin enligt följande:
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 ... */
}
Nu lagras källfilens namn och radnummer där addNewRecord anropades i varje resulterande block som allokerats i felsöknings heapen och rapporteras när blocket granskas.