Udostępnij za pośrednictwem


Sterty CRT debugowania

Ten temat zawiera szczegółowe spojrzenie na stercie debugowania CRT.

W tym temacie

Zarządzanie pamięcią i sterty debugowania

Bloki na stercie debugowania typów

Funkcje sterty debugowania

Za pomocą sterty debugowania

nowe, usuwania i _CLIENT_BLOCKs w C++ debugowania sterty

Funkcje raportowania Państwa sterty

Śledzenie żądań Alokacja sterty

Zarządzanie pamięcią i sterty debugowania

Dwie najbardziej typowe i trudne do rozwiązania problemów, które napotkać programistów będą zastąpione koniec przydzielonego przecieków buforu i pamięci, (nie można zwolnić alokacje, po nie są już potrzebne).Sterty debugowania oferuje zaawansowane narzędzia do rozwiązywania problemów z alokacją pamięci tego rodzaju.

Buduje debugowania poszczególnych funkcji sterty wywołać standardowej lub podstawowej wersji używane w wydaniu.Żądając blok pamięci, debugowania Menedżer sterty przydziela z podstawowej sterty nieco większego bloku pamięci niż zgłoszony, a następnie zwraca wskaźnik do swojej części tego bloku.Załóżmy na przykład, aplikacja zawiera wywołanie: malloc( 10 ).W wersjach zbudowanych funkcja malloc nazywają rutynowych alokacji podstawowej sterty o przydział 10 bajtów.W trybie debugowania, jednak malloc nazywają _malloc_dbg, który będzie wywoływać rutynowych alokacji podstawowej sterty o przydział 10 bajtów plus około 36 bajtów dodatkowej pamięci.Wszystkie wynikowe bloków pamięci w stercie debugowania są połączone na pojedynczej liście połączonego, uporządkowane według kiedy zostały przydzielone.

Dodatkowa pamięć przydzielona przy użyciu procedur sterty debugowania jest używany do informacji księgowych, dla wskaźników, że bloków pamięci debugowania łączy ze sobą, a dla małych buforów po obu stronach danych, aby złapać zastępuje przydzielonego regionu.

Obecnie Struktura nagłówka bloku, używane do przechowywania informacji księgowych sterty debugowania jest zadeklarowany następująco w DBGINT.Plik nagłówkowy H:

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 Buforów po obu stronach obszaru danych użytkownika bloku obecnie rozmiar 4 bajtów, a są wypełnione znanych bajt o wartości używane przez procedur sterty debugowania, aby zweryfikować, że nie został zastąpiony granicach blok pamięci przez użytkownika.Sterty debugowania wypełnia również nowych bloków pamięci z znanej wartości.Jeśli zostanie wybrana opcja Zachowaj zwolnionej bloki sterty połączonej liście, co zostało opisane poniżej, te bloki zwolnionej również są wypełnione znanej wartości.Obecnie wartości rzeczywiste bajt, używane są następujące:

  • NoMansLand (0xFD)
    0XFD wypełnione są obecnie buforów "NoMansLand" po obu stronach pamięci używanej przez aplikację.

  • Bloki zwolnionej (0xDD)
    Bloki zwolnionej, trzymane w sterty debugowania jest połączony wybór, kiedy _CRTDBG_DELAY_FREE_MEM_DF jest ustawiona flaga są obecnie wypełnione 0xDD.

  • Nowe obiekty (0x50)
    Nowe obiekty są wypełnione 0x50, podczas gdy są przydzielone.

    W tym temacie

Bloki na stercie debugowania typów

Każdy blok pamięci na stercie debugowania jest przypisany do jednego z pięciu typów alokacji.Tego typu są śledzone i zgłaszane w różny sposób w celu wykrywania przecieków i sprawozdania Państw.Można określić typ bloku, rozdzielając go przy użyciu bezpośrednie wywołanie jednej z funkcji Alokacja sterty debugowania, takich jak _malloc_dbg.Pięć typów bloków pamięci w stercie debugowania (w nBlockUse członkiem _CrtMemBlockHeader struktury) są następujące:

  • _NORMAL_BLOCK
    Wywołanie malloc lub calloc tworzy Blok normalny.Jeśli zamierzasz używać tylko w przypadku bloków normalnych i nie potrzebują dla bloków klienta, warto zdefiniować _CRTDBG_MAP_ALLOC, co powoduje, że wszystkie alokację sterty wywołuje mają być mapowane na ich odpowiedniki debugowania w kompilacje debugowania.Pozwoli to nazwy i linii numer informacje o plikach o każdym połączeniu alokacji mają być przechowywane w odpowiednich nagłówek bloku.

  • _CRT_BLOCK
    Bloki pamięci przydzielonej wewnętrznie przez wiele funkcji biblioteki uruchomieniowej są oznaczane jako CRT bloki więc mogą być traktowane oddzielnie.W efekcie wykrywania przecieków, a inne operacje muszą podlegać wpływom je.Przydział nigdy nie musi przydzielić i nie może ponownie przydzielić lub wolny blok dowolnego typu CRT.

  • _CLIENT_BLOCK
    Aplikacja mogą śledzić specjalne danej grupy alokacje na potrzeby debugowania, rozdzielając je jako tego typu blok pamięci, przy użyciu jawnych wywołań funkcji debugowania sterty.MFC, na przykład przydziela wszystkim CObjects jako bloki klienta; inne aplikacje zachować pamięci różnych obiektów w blokach klienta.Podtypów bloków klienta można również określić dla większej szczegółowości śledzenia.Aby określić podtypów bloków klienta, przesunięta wyświetlana liczba pozostawionych przez 16 bitów i OR z _CLIENT_BLOCK.Na przykład:

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

    Funkcji dostarczanych przez klienta hak do zatopienia obiekty przechowywane w blokach klienta można zainstalować za pomocą _CrtSetDumpClient, a następnie zostanie wywołana przy każdym bloku klienta jest po cenach dumpingowych przez funkcję debugowania.Ponadto _CrtDoForAllClientObjects może służyć do wywołania danej funkcji dostarczanych przez aplikację dla każdego klienta bloku w stercie debugowania.

  • _FREE_BLOCK
    Normalnie bloków, które są zwalniane są usuwane z listy.Aby sprawdzić, czy zwolnionej pamięci nie wciąż napisano w celu lub do symulacji warunków braku pamięci, możesz zachować zwolnionej bloki na listę łączoną, oznaczony jako wolne i podać wartość bajtu znanych (obecnie 0xDD).

  • _IGNORE_BLOCK
    Istnieje możliwość wyłączyć operacji debugowania sterty przez pewien czas.W tym czasie bloków pamięci są przechowywane na liście, ale są oznaczone jako Ignoruj bloków.

Aby określić typ i podtyp danego bloku, należy użyć funkcji _CrtReportBlockType i makra _BLOCK_TYPE i _BLOCK_SUBTYPE.Makra są określone (w crtdbg.h), jak następuje:

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

W tym temacie

Funkcje sterty debugowania

Wiele funkcji sterty debugowania muszą być dostępne z w kodzie.W poniższej sekcji opisano niektóre funkcje i sposób ich użycia.

  • _CrtCheckMemory
    Można zastosować wywołanie do _CrtCheckMemory, na przykład, aby sprawdzić integralność sterty w dowolnym momencie.Ta funkcja sprawdza każdy blok pamięci na stercie, sprawdza, czy informacje nagłówka bloku pamięci jest prawidłowy i potwierdza, że bufory nie zostały zmodyfikowane.

  • _CrtSetDbgFlag
    Można kontrolować, jak sterty debugowania informacje o alokacji używających flaga wewnętrzna, _crtDbgFlag, którą można odczytywać i ustawiać za pomocą _CrtSetDbgFlag funkcji.Zmiana tej flagi, można poinstruować sterty debugowania, sprawdź, czy przecieki pamięci, kiedy program i zgłoszenie nieszczelności, które są wykrywane.Podobnie można określić, bloki zwolnionej pamięci nie można usunąć z listy łączonej, aby symulować sytuacje braku pamięci.Po zaznaczeniu sterty tych bloków zwolnionej są sprawdzane w całości w celu zapewnienia, że przywóz ten nie był zakłócony.

    _CrtDbgFlag Flaga zawiera następujące pola bitowa:

    Pole bitowe

    Domyślne

    wartość

    Opis

    _CRTDBG_ALLOC_MEM_DF

    Na

    Włącza debugowanie alokacji.Kiedy ten bit jest wyłączony, przyznane środki są połączonych ze sobą, ale jest ich typ bloku _IGNORE_BLOCK.

    _CRTDBG_DELAY_FREE_MEM_DF

    Wyłączanie

    Pamięci uniemożliwia faktycznie zwalniana, jeśli chodzi o symulowanie ilość pamięci jest mała.Jeśli ten bit jest włączona, zwolnionej bloki są trzymane w połączonej listy sterty debugowania, ale są oznaczone jako _FREE_BLOCK i podać wartość bajtu specjalne.

    _CRTDBG_CHECK_ALWAYS_DF

    Wyłączanie

    Powoduje, że _CrtCheckMemory się nazywać na każdym alokacji i dezalokacji.To spowalnia wykonanie, ale szybko połowy błędy.

    _CRTDBG_CHECK_CRT_DF

    Wyłączanie

    Powoduje, że bloki oznaczone jako typ _CRT_BLOCK mają zostać uwzględnione w operacji wykrywania przecieków i różnica stanu.Jeśli ten bit jest wyłączona, pamięci używane wewnętrznie przez biblioteki uruchomieniowej jest ignorowany podczas takiej operacji.

    _CRTDBG_LEAK_CHECK_DF

    Wyłączanie

    Powoduje, że przeciek kontroli przeprowadzanych na terytorium program za pośrednictwem wywołania _CrtDumpMemoryLeaks.Jeśli aplikacja nie powiodło się zwolnić pamięć, która go przydzielona, zostanie wygenerowany raport o błędach.

W tym temacie

Za pomocą sterty debugowania

Wszystkie wywołania funkcji sterty, takich jak malloc, free, calloc, realloc, new, i delete rozwiązać debugowania wersjach tych funkcji, które działają na stercie debugowania.Gdy wolnego bloku pamięci, sterty debugowania automatycznie sprawdza integralność buforów po obu stronach obszaru przydzielonego i wystawia raport o błędach, w przypadku zastępowania.

Aby użyć debugowania sterty

  • Link do zbudowania debugowania aplikacji z wersją biblioteki uruchomieniowej C debugowania.

Aby zmienić jedno lub więcej pól bitowych _crtDbgFlag i Utwórz nowy stan flagi

  1. Wywołać _CrtSetDbgFlag z newFlag parametr wartość _CRTDBG_REPORT_FLAG (Aby uzyskać bieżące _crtDbgFlag Państwo) i przechowywać zwrócona wartość w zmiennej tymczasowej.

  2. Włącz wszystkie bity przez OR- ing (logiczną | symbol) zmiennej tymczasowej z odpowiednich masek bitowych (reprezentowane przez stałe manifestu w kodzie aplikacji).

  3. Wyłączyć inne kawałki przez AND- ing (logiczną & symbol) zmiennej z NOT (logiczną ~ symbol) z odpowiednich masek bitowych.

  4. Call _CrtSetDbgFlag z newFlag parametr ustawiony na wartość przechowywana w zmiennej tymczasowej, aby utworzyć nowy stan dla _crtDbgFlag.

Na przykład, następujące wiersze kodu włączyć funkcję automatycznego wykrywania wycieków i wyłączyć sprawdzanie bloków 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 );

nowe, usuwania i _CLIENT_BLOCKs w C++ debugowania sterty

Wersje do debugowania biblioteki uruchomieniowej C zawierają wersje do debugowania C++ new i delete podmiotów gospodarczych.Klienci korzystający z _CLIENT_BLOCK typu alokacji, należy wywołać do programu new operatora bezpośrednio lub utworzyć makra, które zastępują new operatora w trybie debugowania, jak pokazano w poniższym przykładzie:

/* 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 );
}

Do programu delete works operatora z blokiem wszystkie typy i nie wymaga żadnych zmian w programie podczas kompilowania wersji.

Funkcje raportowania Państwa sterty

_CrtMemState

Aby przechwycić podsumowania Migawka stanu sterty w danym momencie, używając struktury _CrtMemState zdefiniowane w CRTDBG.GODZ.:

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;

Ta struktura zapisuje wskaźnik do pierwszego bloku (najbardziej niedawno przydzielonego) w połączonej listy sterty debugowania.Następnie, w dwóch tablicach rejestruje zablokować ile każdego rodzaju pamięci (_NORMAL_BLOCK, _CLIENT_BLOCK, _FREE_BLOCK, i tak dalej) są na liście i liczbę bajtów alokowanych każdego rodzaju bloku.Wreszcie rejestruje największą liczbą bajtów alokowany na stercie jako całość do tej pory i liczbę bajtów przydzieliła.

Inne funkcje raportowania CRT

Następujące funkcje raportu stanu i zawartość sterty i użyć tych informacji w celu wykrycia przecieków pamięci i innych problemów.

Funkcja

Opis

_CrtMemCheckpoint

Zapisywana jest Migawka sterty w _CrtMemState struktury dostarczonych przez aplikację.

_CrtMemDifference

Porównuje dwa struktur państwowych pamięci, zapisuje różnicę między nimi w strukturze państwa trzeciego i zwraca wartość PRAWDA, jeśli dwa Państwa są różne.

_CrtMemDumpStatistics

Zrzuca danego _CrtMemState struktury.Struktura może zawierać Migawka stanu sterty debugowania w danym momencie lub różnicę między dwoma migawek.

_CrtMemDumpAllObjectsSince

Zrzuca informacje o wszystkich obiektów przydzielone ponieważ danym migawki sterty lub od początku realizacji.Za każdym razem, gdy to Zrzuca _CLIENT_BLOCK blok, wywołuje funkcję hak dostarczonych przez aplikację, jeśli jeden został zainstalowany przy użyciu _CrtSetDumpClient.

_CrtDumpMemoryLeaks

Określa, czy wszystkie pamięci przecieków miały miejsce od momentu rozpoczęcia wykonywania programu, a jeśli tak, zrzuca wszystkie obiekty przydzielonego.Za każdym razem, gdy _CrtDumpMemoryLeaks Zrzuca _CLIENT_BLOCK blok, wywołuje funkcję hak dostarczonych przez aplikację, jeśli jeden został zainstalowany przy użyciu _CrtSetDumpClient.

W tym temacie

Śledzenie żądań Alokacja sterty

Chociaż identyfikowania źródła nazwy i linii numer akt w który assert lub makro raportowania jest wykonywany jest często bardzo pomocne w odnalezieniu przyczyny problemu, nie jest taka sama jak może być istotne w funkcji alokacji sterty.Podczas gdy makra można wstawiać w wielu punktach właściwe w drzewie logiki aplikacji, przydział jest często ukryte w specjalnej procedury, która jest wywoływana z wielu różnych miejscach w wielu różnych okresach.Pytanie jest zwykle nie wykonała alokację zły przez co linia kodu, ale raczej prezentującej tysięcy alokacje dokonane przez ta linia kodu było źle i dlaczego.

Unikatowe numery żądania alokacji i _crtBreakAlloc

Najprostszym sposobem identyfikowania wywołanie alokacji sterty szczególnych, które poszło źle jest do skorzystania z alokacji unikatowy numer żądania, skojarzone z każdego bloku w stercie debugowania.Gdy informacje o bloku zostanie zgłoszona przez jedną z funkcji zrzutu, ten numer żądania alokacji jest ujęte w nawiasy klamrowe (na przykład {36}").

Gdy znasz numer żądania alokacji nieprawidłowo przydzielonego bloku, można przekazać to pod numer _CrtSetBreakAlloc do utworzenia punktu przerwania.Wykonanie spowoduje przerwanie tuż przed Alokowanie bloku, a można cofnąć, aby ustalić, jakie rutynowych był odpowiedzialny za złe połączenie.Aby uniknąć ponownej kompilacji, można to osiągnąć to samo co narzędzie Debugger przez ustawienie _crtBreakAlloc do numer żądania alokacji są Państwo zainteresowani.

Tworzenie wersji debugowania procedur swojej alokacji

Nieco bardziej skomplikowane podejście jest utworzenie wersje do debugowania własne procedury alokacji, porównywalne do _dbg wersji funkcji Alokacja sterty.Można przekazać pliku źródłowego i linia argumentów liczbowych, za pośrednictwem podstawowych procedur alokacji sterty, a od razu można zobaczyć, skąd pochodzi zły alokacji.

Na przykład załóżmy, że aplikacja zawiera powszechnie stosowane rutynowe, podobny do następującego:

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

W pliku nagłówkowym można dodać kod, taki jak poniżej:

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

Następnie można zmienić przydział w rutynowe tworzenie rekordów się następujące zmiany:

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 ... */
}

Teraz plik nazwy i linii numer źródła gdzie addNewRecord została wywołana będą przechowywane w każdym bloku wynikowy alokowany na stercie debugowania i jest informowany podczas tego bloku jest badany.

W tym temacie

Zobacz też

Inne zasoby

Debugowanie kodu macierzystego

Techniki debugowania CRT