Content of this section
-
Memory Management and debugging heap
-
Describes the "debug" version of the heap function. These functions solve two hard-to-solve memory allocation problems: rewrite the end of the allocated buffer and Memory leakage (they cannot be released after they are no longer needed ).
-
Block types in the debugging heap
-
Describes the five allocation types allocated to memory blocks in the debugging heap. These allocation types are tracked and reported in different ways for the purpose of Leak Detection and status report.
-
Debugging heap
-
Provides information about the use of the debugging heap. Information includes: Which calls are used for the debug version, what will happen when the memory block is released, and which debugging functions must be accessed and changed from inside the code
_ CrtdbgflagSteps to create a new state of a flag, as well as an explanation of how to enable automatic leak detection and how to disable
_ Crt_blockSample Code for checking data blocks.
-
Debugging heap in C ++
-
Discuss C ++
NewAnd
DeleteThe "debug" version and usage of the operator
_ Crtdbg_map_alloc.
-
Heap Status Report Function
-
Description
_ CrtmemstateStructure, which can be used to capture the summary snapshot of the heap status. This topic also lists some CRT functions that report heap status and content and use this information to help detect memory leaks and other problems.
-
Track heap allocation requests
-
Contains methods used to identify specific heap allocation calls with errors.
Related chapters
-
CRT debugging technology
-
Link to the debugging technology for the C Runtime Library, including: using the CRT debugging library, macro for reporting,
MallocAnd
_ Malloc_dbgDifferences between them, compiling debugging hook functions, and CRT debugging heap (refer to msnd ).
Memory Management and debugging heap
The two most common and difficult problems that programmers encounter are rewriting the end of the allocated buffer and Memory leakage (failing to release it after some allocation is no longer required ). The debugging heap provides powerful tools to solve such memory allocation problems.
"Debug" version of heap Functions
The "debug" version of the heap function calls the standard or base version used in the "release" version. When a memory block is requested, the debugging heap manager allocates a memory block slightly greater than the requested block from the base heap, and returns a pointer to your part of the block. For example, assume that the application contains a call:malloc( 10 )
. In the "release" version, The baseline heap allocation routine is called to allocate 10 bytes to the request. However, in the "debug" version,MallocCall The function then calls the baseline heap allocation routine to allocate 10 bytes with about 36 bytes of additional memory. All memory blocks generated in the debugging heap are connected in a single link list and sorted by the allocation time.
The additional memory allocated by the debugging heap routine is used to store the bookkeeping information and to store pointers linking the debugging memory blocks together, and form a small buffer on both sides of the data (used to capture the rewrite of the allocated area ).
Currently, the block header structure used to store the debugging heap bookkeeping information is declared in the dbgint. h header file as follows:
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];
*/
The user data area of the blockNoMansLand
The current buffer size is 4 bytes and is filled with the known byte values used by the debugging heap routine to verify that the user memory block limit has not been rewritten. The debugging heap also fills in new memory blocks with known values. If you choose to retain the released blocks in the heap Link List (as described below), these released blocks are also filled with known values. Currently, the actual byte value is as follows:
-
Nomansland (0xfd) (defencde data)
-
The nomansland Buffer on both sides of the memory used by the application is currently filled with 0xfd.
-
Released block (0xdd) (dead data)
-
Set
_ Crtdbg_delay_free_mem_dfThe unused released blocks are retained in the Link List of the debugging heap. Currently, the unused released blocks are filled with 0xdd.
-
New object (0xcd) (cleared data)
-
When new objects are allocated, these objects are filled with 0xcd.
Block types in the debugging heap
Each memory block in the debugging heap is allocated with one of five allocation types. These types are tracked and reported differently for the purpose of Leak Detection and status reporting. You can specify the block type by allocating a function (such . Five memory block types in the debug heap_ CrtmemblockheaderStructureNblockuse) As follows:
-
_ Normal_block
-
Pair Or To create a "normal" block. If you want to use only the "common" block instead of the "client" block, you may want to define , Which causes all heap allocation calls to map to their debugging equivalents in the "debug" version. This allows you to store the file name and row number information about each allocation call to the corresponding block header.
-
_ Crt_block
-
Memory blocks allocated by many Runtime library functions are marked as CRT blocks so that they can be processed separately. As a result, the leakage detection and other operations do not need to be affected by these blocks. You can never allocate, reassign, or release any CRT block.
-
_ Client_block
-
For debugging purposes, the application can specifically track a group of given allocations by allocating them as memory blocks by explicitly calling the debug heap functions. For example, MFC assigns all
CobjectsOther applications may keep different memory objects in the "client" block. You can also specify the sub-type of the "client" Block for greater tracking granularity. To specify the subtype of the "client" block, move this number to the left of 16 digits and
_ Client_blockProceed
OrOperation. For example:
#define MYSUBTYPE 4
freedbg(pbData, _CLIENT_BLOCK|(MYSUBTYPE<<16));
Hook functions provided by the client (used to dump objects stored in the "client" Block) can be used Then, the hook function is called whenever the debugging function dumps the "client" block. Similarly, for each "client" block in the debugging heap, you can use To call the given functions provided by the application.
-
_ Free_block
-
The released block is usually removed from the list. To check whether data is still being written to the released memory, or to Simulate Memory insufficiency, you can choose to reserve the released block on the Link List and mark it as "available ", fill in with the known byte value (currently 0xdd.
-
_ Ignore_block
-
It is possible to disable the debugging heap operation within a period of time. During this period, the memory blocks are retained on the list, but are marked as "ignored" blocks.
To determine the type and sub-type of the given block, use Functions and_ Block_typeAnd_ Block_subtypeMacro. The macro definition (in crtdbg. h) is as follows:
# DEFINE _ block_type (Block) (Block & 0 xFFFF)
# DEFINE _ block_subtype (Block) (Block> 16 & 0 xFFFF)
Debugging heap
Heap functions (suchMalloc,Free,Calloc,Realloc,NewAndDelete) Is resolved to the "debug" version that these functions run in the debugging heap. When the memory block is released, the debugging heap automatically checks the integrity of the buffer zones on both sides of the allocated area. If the buffer is rewritten, an error report is reported.
Use debugging heap
- Use the "debug" version of the C Runtime Library to link the debugging version of the application.
Debug the heap function accessed from inside the code
-
_ Crtcheckmemory
-
Many debugging heap functions must be accessed from the code. For example, you can use To check the integrity of the heap. This function checks every memory block in the heap, verifies that the memory block header information is valid, and confirms that the buffer has not been modified.
-
_ Crtsetdbgflag
-
Internal flag can be used To control the heap trace allocation method. This flag can be used. Read and set functions. By changing this flag, you can instruct the debugging heap to check for memory leaks when the program exits and report all detected leaks. Similarly, you can specify not to remove released memory blocks from the link list to simulate insufficient memory. When you check the heap, the released blocks are fully checked to ensure they are not disturbed.
_ CrtdbgflagThe flag contains the following fields:
Bit domain |
Default Value |
Description |
_ Crtdbg_alloc_mem_df |
On |
Enable debugging allocation. When this bit is off, the allocation is still linked together, but their block type is_ Ignore_block. |
_ Crtdbg_delay_free_mem_df |
Off |
This prevents the actual release of memory, which is the same as the simulated memory shortage. When this bit is on, the released block is retained in the Link List of the debugging heap, but marked_ Free_blockAnd fill it with special byte values. |
_ Crtdbg_check_always_df |
Off |
It is called every time it is assigned and released._ Crtcheckmemory. This slows down the execution, but can quickly catch errors. |
_ Crtdbg_check_crt_df |
Off |
As a result_ Crt_blockBlock types are included in leakage detection and status difference operations. When this bit is off, the memory used inside the Runtime Library is ignored during these operations. |
_ Crtdbg_leak_check_df |
Off |
As a result, when the program exits, it is called To perform the leak check. If the application fails to release all its allocated memory, an error report is generated. |
Change one or more _ crtdbgflag fields and create a new flag status
- InNewflagSet the parameter_ Crtdbg_report_flagWhen calling_ Crtsetdbgflag(To obtain the current_ CrtdbgflagStatus), and store the return value in a temporary variable.
- Open any bit and block the temporary variables from the corresponding bit (represented by the list constant in the application code ).OrOperation (by bit | symbol ).
- Disable other bits and blockNot(By bit ~ Symbol ).AndOperation (by bit & symbol ).
- InNewflagWhen the parameter is set to the value stored in the temporary variable_ CrtsetdbgflagTo create_ Crtdbgflag.
For example, the following code is used to enable automatic leak detection and disable the check._ Crt_blockBlock Type:
// 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 );
Debugging heap in C ++
The "debug" version of the C Runtime Library contains the C ++NewAndDeleteThe "debug" version of the operator. If the C ++ Code defines , ThenNewAll instances are mapped to the "debug" version, which records the source file and row number information.
If you want to use_ Client_blockAllocation type, please do not define_ Crtdbg_map_alloc. Instead, it must be called directly.NewOr create or replaceNewThe Macro of the operator, as shown in the following example:
/* 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
Compile options needed: /Zi /D_DEBUG /MLd
* or use a
* Default Workspace for a Console Application to
* build a Debug version
*/
#include "crtdbg.h"
#include "mydbgnew.h"
#ifdef _DEBUG
#define new DEBUG_CLIENTBLOCK
#endif
int main( ) {
char *p1;
p1 = new char[40];
_CrtMemDumpAllObjectsSince( NULL );
}
DeleteThe "debug" version of the operator can be used for all block types, and the program does not need to be changed when the "release" version is compiled.
Heap Status Report Function
Several functions can report the debugging heap content at a given time.
_ Crtmemstate
To capture a summary snapshot of the heap status at a given time point, use_ CrtmemstateStructure:
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;
This structure saves the pointer to the first (recently allocated) block in the list of links pointing to the debugging heap. Then, it records each type of memory block in the list in two arrays (_ Normal_block,_ Client_block,_ Free_block), And the number of bytes allocated in each type of block. Finally, it records the maximum number of bytes allocated in the heap until this point and the number of currently allocated bytes.
Other CRT report functions
The following functions report the heap status and content and use this information to help detect memory leaks and other problems:
Function |
Description |
|
In_ CrtmemstateStructure. |
|
Compare two memory status structures and save the difference between the two in the third State structure. If the two States are different, the system returnsTrue. |
|
Dump the given_ CrtmemstateStructure. This structure may contain the snapshot of the heap state debugging at a given time or the difference between two snapshots. |
|
Dump information of all objects allocated since or since the execution of a given snapshot of the heap. If you have used_ CrtsetdumpclientIf the hook function is installed,_ CrtmemdumpallobjectssinceEach dump_ Client_blockThe hook function provided by the application is called. |
|
Determine whether memory leakage has occurred since the execution of the program. If yes, dump all allocated objects. If you have used_ CrtsetdumpclientIf the hook function is installed,_ CrtdumpmemoryleaksEach dump_ Client_blockThe hook function provided by the application is called. |
Track heap allocation requests
Although finding out the source file name and row number that execute assertions or report Macros in it is often useful for locating the cause of the problem, this may not be the case for heap allocation functions. Although macros can be inserted into many appropriate points in the logic tree of the application, allocation is often hidden in special routines, which are called from many different locations at many different times. The problem is usually not how to determine which line of code is allocated incorrectly, but how to determine which of the thousands of times the code is allocated incorrectly and the cause.
Unique allocation request number and _ crtbreakalloc
The simplest way to identify a specific heap allocation call with an error is to use the unique allocation request number associated with each block in the debugging heap. When one of the dump functions reports information about a block, the allocation request number is enclosed in braces (for example, "{36 }").
After you know the allocation Request ID of an incorrect allocation block, you can pass the ID To create a breakpoint. Execution will be interrupted just before the block is allocated. You can trace back to determine which routine has performed an incorrect call. To avoid re-compilation, you can perform the same operation in the debugger by setting_ CrtbreakallocID of the allocation request that you are interested in.
Create the "debug" version of the allocation routine
A slightly complicated method is to create the "debug" version of your own allocation routine, which is equivalent to the heap Allocation Function_ DbgVersion. Then, you can pass the source file and row number parameters to the baseline heap allocation routine and immediately see the error distribution source.
For example, assume that your application contains a common routine similar to the following:
int addNewRecord(struct RecStruct * prevRecord,
int recType, int recAccess)
{
// ...code omitted through actual allocation...
if ((newRec = malloc(recSize)) == NULL)
// ... rest of routine omitted too ...
}
In the header file, you can add the following code:
#ifdef _DEBUG
#define addNewRecord(p, t, a) /
addNewRecord(p, t, a, __FILE__, __LINE__)
#endif
Next, you can change the allocation in the record creation routine as follows:
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 ... */
}
CalladdNewRecord
The source file name and row number of will be stored in each generated block (these blocks are allocated in the debugging heap), and will be reported when the block is checked.