Inside CRT: Debug Heap Management 选择自 huanghycn 的 Blog

本文详细解释了在使用Visual Studio进行调试时,如何通过特定的内存值如0xCDCDCDCD和0xDDDDDDDD来检测内存泄漏和损坏。介绍了通过new/delete及malloc/free等函数进行内存分配与释放的具体过程。

When you compile a debug build of your program with Visual Studio and run it in debugger, you can see that the memory allocated or deallocated has funny values, such as 0xCDCDCDCD or 0xDDDDDDDD. This is the result of the work Microsoft has put in to detect memory corruption and leaks in the Win32 platform. In this article, I will explain how memory allocation/deallocation is done via new/delete or malloc/free.

First, I will explain what all these values that you see, like CD, DD, and so forth, mean.

ValueNameDescription
0xCDClean MemoryAllocated memory via malloc or new but never written by the application.
0xDDDead MemoryMemory that has been released with delete or free. It is used to detect writing through dangling pointers.
0xFDFence MemoryAlso known as "no mans land." This is used to wrap the allocated memory (like surrounding it with fences) and is used to detect indexing arrays out of bounds.
0xAB(Allocated Block?)Memory allocated by LocalAlloc().
0xBAADF00DBad FoodMemory allocated by LocalAlloc() with LMEM_FIXED, but not yet written to.
0xCC When the code is compiled with the /GZ option, uninitialized variables are automatically assigned to this value (at byte level).

If you take a look at DBGHEAP.C, you can see how some of these values are defined:

static unsigned char _bNoMansLandFill = 0xFD;   /* fill no-man's land with this */static unsigned char _bDeadLandFill   = 0xDD;   /* fill free objects with this */static unsigned char _bCleanLandFill  = 0xCD;   /* fill new objects with this */

Before going any further, take a look at the memory management function that I will refer in this article.

FunctionDescription
mallocC/C++ function that allocates a block of memory from the heap. The implementation of the C++ operator new is based on malloc.
_malloc_dbgDebug version of malloc; only available in the debug versions of the run-time libraries. _malloc_dbg is a debug version of the malloc function. When _DEBUG is not defined, each call to _malloc_dbg is reduced to a call to malloc. Both malloc and _malloc_dbg allocate a block of memory in the base heap, but _malloc_dbg offers several debugging features: buffers on either side of the user portion of the block to test for leaks, a block type parameter to track specific allocation types, and filename/linenumber information to determine the origin of allocation requests.
freeC/C++ function that frees an allocated block. The implementation of C++ operator delete is based on free.
_free_dbgDebug version of free; only available in the debug versions of the run-time libraries. The _free_dbg function is a debug version of the free function. When _DEBUG is not defined, each call to _free_dbg is reduced to a call to free. Both free and _free_dbg free a memory block in the base heap, but _free_dbg accommodates two debugging features: the ability to keep freed blocks in the heap's linked list to simulate low memory conditions and a block type parameter to free specific allocation types.
LocalAlloc
GlobalAlloc
Win32 API to allocate the specified number of bytes from the heap. Windows memory management does not provide a separate local heap and global heap.
LocalFree
GlobalFree
Win32 API free the specified local memory object and invalidates its handle.
HeapAllocWin32 API allocates a block of memory from a heap. The allocated memory is not movable.
HeapFreeWin32 API frees a memory block allocated from a heap by the HeapAlloc or HeapReAlloc function.

There are many other functions that deal with memory management. For a complete view please refer to MSDN.

Note: Because this article is about memory management in a debug build, all the references to malloc and free in the following are actually references to their debug versions, _malloc_dbg and _free_dbg.

Compile the following code and run it in the debugger, walking step by step into it to see how memory is allocated and deallocated.

int main(int argc, char* argv[]){   char *buffer = new char[12];   delete [] buffer;   return 0;}

Here, 12 bytes are dynamically allocated, but the CRT allocates more than that by wrapping the allocated block with bookkeeping information. For each allocated block, the CRT keeps information in a structure called _CrtMemBlockHeader, which is declared in DBGINT.H:

#define nNoMansLandSize 4typedef struct _CrtMemBlockHeader{        struct _CrtMemBlockHeader * pBlockHeaderNext;        struct _CrtMemBlockHeader * pBlockHeaderPrev;        char *                      szFileName;        int                         nLine;        size_t                      nDataSize;        int                         nBlockUse;        long                        lRequest;        unsigned char               gap[nNoMansLandSize];        /* followed by:         *  unsigned char           data[nDataSize];         *  unsigned char           anotherGap[nNoMansLandSize];         */

 

} _CrtMemBlockHeader;

It stores the following information:

FieldDescription
pBlockHeaderNextA pointer to the next block allocated, but next means the previous allocated block because the list is seen as a stack, with the latest allocated block at the top.
pBlockHeaderPrevA pointer to the previous block allocated; this means the block that was allocated after the current block.
szFileNameA pointer to the name of the file in which the call to malloc was made, if known.
nLineThe line in the source file indicated by szFileName at which the call to malloc was made, if known.
nDataSizeNumber of bytes requested
nBlockUse0 - Freed block, but not released back to the Win32 heap
1 - Normal block (allocated with new/malloc)
2 - CRT blocks, allocated by CRT for its own use
lRequestCounter incremented with each allocation
gapA zone of 4 bytes (in the current implementation) filled with 0xFD, fencing the data block, of nDataSize bytes. Another block filled with 0xFD of the same size follows the data.

Most of the work of heap block allocation and deallocation are made by HeapAlloc() and HeapFree(). When you request 12 bytes to be allocated on the heap, malloc() will call HeapAlloc(), requesting 36 more bytes.

blockSize = sizeof(_CrtMemBlockHeader) + nSize + nNoMansLandSize;

malloc requests space for the 12 bytes we need (nSize), plus 32 bytes for the _CrtMemBlockHeader structure and another nNoMansLandSize bytes (4 bytes) to fence the data zone and close the gap.

But, HeapAlloc() will allocate even more bytes: 8 bytes below the requested block (that is, at a lower address) and 32 above it (that is, at a bigger address). It also initializes the requested block to 0xBAADF00D (bad food).

Then, malloc() fills the _CrtMemBlockHeader block with information and initializes the data block with 0xCD and no mans land with 0xFD.

Here is a table that shows how memory looks after the call to HeapAlloc() and after malloc() returns. For a complete situation, see the last table. (Note: All values are in hex.)

Addressafter HeapAlloc()after malloc()
00320FD8
00320FDC
00320FE0
00320FE4
00320FE8
00320FEC
00320FF0
00320FF4
00320FF8
00320FFC
00321000
00321004
00321008
0032100C
00321010
00321014
00321018
0032101C
00321020
00321024
00321028
0032102C
09 00 09 01
E8 07 18 00
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
0D F0 AD BA
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00
09 00 09 01
E8 07 18 00
98 07 32 00
00 00 00 00
00 00 00 00
00 00 00 00
0C 00 00 00
01 00 00 00
2E 00 00 00
FD FD FD FD
CD CD CD CD
CD CD CD CD
CD CD CD CD
FD FD FD FD
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00

Colors:

  • Green: win32 bookkeeping info
  • Blue: block size requested by malloc and filled with bad food
  • Magenta: _CrtMemBlockHeader block
  • Red: no mans land
  • Black: requested data block

In this example, after the call to malloc() returns, buffer will point to memory address 0x00321000.

When you call delete/free, the CRT will set the block it requested from HeapAlloc() to 0xDD, indicating this is a free zone. Normally after this, free() will call HeapFree() to give back the block to the Win32 heap, in which case the block will be overwritten with 0xFEEEEEEE, to indicate Win32 heap free memory.

You can avoid this by using the CRTDBG_DELAY_FREE_MEM_DF flag to _CrtSetDbgFlag(). It prevents memory from actually being freed, as for simulating low-memory conditions. When this bit is on, freed blocks are kept in the debug heap's linked list but are marked as _FREE_BLOCK. This is useful if you want to detect dangling pointers errors, which can be done by verifying if the freed block is written with 0xDD pattern or something else. Use _CrtCheckMemory() to verify the heap.s integrity.

The next table shows how the memory looks during the free(), before HeapFree() is called and afterwards.

AddressBefore HeapFree()After HeapFree()
00320FD8
00320FDC
00320FE0
00320FE4
00320FE8
00320FEC
00320FF0
00320FF4
00320FF8
00320FFC
00321000
00321004
00321008
0032100C
00321010
00321014
00321018
0032101C
00321020
00321024
00321028
0032102C
09 00 09 01
5E 07 18 00
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
DD DD DD DD
AB AB AB AB
AB AB AB AB
00 00 00 00
00 00 00 00
79 00 09 00
EE 04 EE 00
40 05 32 00
40 05 32 00
82 00 09 01
5E 04 18 00
E0 2B 32 00
78 01 32 00
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE
EE FE EE FE

Colors:

  • Green: win32 bookkeeping info
  • Blue: CRT block filled with dead memory
  • Gray: memory given back to win32 heap

The two tables above are put in a single, more detailed, table below:

Address (hex)OffsetHeapAllocmallocFree before HeapFreeFree after HeapFreeDescription
00320FD8-4001090009010900090109000901090082Win32 Heap info
00320FDC-36001807E8001807E80018075E0018045EWin32 Heap info
00320FE0-32BAADF00D00320798DDDDDDDD00322BE0pBlockHeaderNext
00320FE4-28BAADF00D00000000DDDDDDDD00320178pBlockHeaderPrev
00320FE8-24BAADF00D00000000DDDDDDDDFEEEEEEEszFileName
00320FEC-20BAADF00D00000000DDDDDDDDFEEEEEEEnLine
00320FF0-16BAADF00D0000000CDDDDDDDDFEEEEEEEnDataSize
00320FF4-12BAADF00D00000001DDDDDDDDFEEEEEEEnBlockUse
00320FF8-8BAADF00D0000002EDDDDDDDDFEEEEEEElRequest
00320FFC-4BAADF00DFDFDFDFDDDDDDDDDFEEEEEEEgap (no mans land)
003210000BAADF00DCDCDCDCDDDDDDDDDFEEEEEEEData requested
00321004+4BAADF00DCDCDCDCDDDDDDDDDFEEEEEEEData requested
00321008+8BAADF00DCDCDCDCDDDDDDDDDFEEEEEEEData requested
0032100C+12BAADF00DFDFDFDFDDDDDDDDDFEEEEEEENo mans land
00321010+16ABABABABABABABABABABABABFEEEEEEEWin32 Heap info
00321014+20ABABABABABABABABABABABABFEEEEEEEWin32 Heap info
00321018+24000000000000000000000000FEEEEEEEWin32 Heap info
0032101C+28000000000000000000000000FEEEEEEEWin32 Heap info
00321020+32000900790009007900090079FEEEEEEEWin32 Heap info
00321024+3600EE04EE00EE04EE00EE04EEFEEEEEEEWin32 Heap info
00321028+40003205400032054000320540FEEEEEEEWin32 Heap info
0032102C+44003205400032054000320540FEEEEEEEWin32 Heap info

About the Author
Marius Bancila is a software developer working for a company that provides industrial automation solutions, but he is mainly focused on GUI design with MFC. When he discovered the .NET framework quickly fell inlove. He considers that CodeGuru is the best place on internet to spend time on.

内容概要:本文系统研究了基于CNN-SVM的卷积神经网络与支持向量机融合的数据分类预测方法,聚焦其在工业故障识别中的应用,提供了完整的Matlab代码实现。通过CNN提取输入数据的深层空间特征,再由SVM进行高精度分类,充分发挥两者优势,有效提升了故障识别的准确性、鲁棒性与泛化能力。该方法特别适用于处理电力系统、机械设备等领域的高维、非线性、强噪声监测数据,在变压器故障诊断、轴承缺陷识别等场景中具有重要应用价值。文档还整合了机器学习、深度学习、图像处理、路径规划、电力系统优化等多个前沿科研方向的技术资源,配套大量Matlab/Simulink仿真案例与Python代码,全面支持科研复现与工程实践。; 适合人群:具备一定编程基础,熟练掌握Matlab或Python语言,从事电气工程、自动化、人工智能、机械故障诊断等相关领域研究的研发人员及高校研究生; 使用场景及目标:① 实现工业设备的状态监测与多类别故障分类;② 深入理解CNN与SVM融合模型的设计原理与工程实现细节;③ 借助所提供的丰富算法案例开展科研复现、模型优化与系统仿真验证; 阅读建议:建议按照文档目录结构系统化学习,结合百度网盘提供的完整代码资源进行动手实践,重点关注CNN特征提取层与SVM分类器之间的数据接口设计与参数调优策略,同时可延伸学习文中涉及的其他智能算法及其在电力系统、信号处理等领域的交叉应用,全面提升科研创新能力。
内容概要:本文围绕“考虑电动汽车灵活性的微网多时间尺度协调调度”展开研究,提出了一种基于Matlab代码实现的优化调度模型。该模型深入挖掘电动汽车作为灵活可控负荷与分布式储能单元的双重潜力,通过构建日前、日内及实时等多时间尺度的协调调度机制,有效应对光伏发电的间歇性与波动性,实现微电网内部功率的动态平衡。研究综合集成了电动汽车集群的有序充放电管理、储能系统协同优化与多种需求响应策略,建立了以系统运行成本最小化、可再生能源消纳最大化及供电可靠性最优化为目标的综合数学模型,并采用Matlab进行仿真求解。结果表明,所提方法能显著平抑功率波动,优化源-荷-储资源的时空配置,提升微电网运行的经济性与稳定性。; 适合人群:电气工程、能源与动力工程、控制科学与工程、电力系统及其自动化等专业的研究生、高校科研人员,以及从事智能电网、微电网规划、电动汽车与电网互动(V2G)技术研发的工程技术人员。; 使用场景及目标:①研究高比例可再生能源接入背景下,含大规模电动汽车的微电网协同优化运行策略;②掌握多时间尺度滚动优化的建模思想与Matlab/Simulink仿真技术;③探索电动汽车聚合商参与电力市场辅助服务的可行路径与效益评估方法; 阅读建议:建议读者结合提供的Matlab代码进行复现与调试,深入理解目标函数构建、约束条件处理及求解器调用等关键技术环节,可尝试引入电池老化模型、用户出行行为不确定性等更贴近实际的因素,以深化研究的实用性与前瞻性。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值