Finding Memory Leaks Using the CRT Library

Visual Studio 2010
3 out of 14 rated this helpful Rate this topic

This topic applies to:

Edition

Visual Basic

C#

F#

C++

Web Developer

Express

Topic does not apply Topic does not apply Topic does not apply

Native only

Topic does not apply

Pro, Premium, and Ultimate

Topic does not apply Topic does not apply Topic does not apply

Native only

Topic does not apply

Memory leaks, defined as the failure to correctly deallocate memory that was previously allocated, are among the most subtle and hard-to-detect bugs in C/C++ applications. A small memory leak might not be noticed at first, but over time, a progressive memory leak can cause symptoms that range from decreased performance to crashing when the application runs out of memory. Worse, a leaking application that uses up all available memory can cause another application to crash, creating confusion as to which application is responsible. Even seemingly harmless memory leaks might be symptomatic of other problems that should be corrected.

The Visual Studio debugger and C Run-Time (CRT) libraries provide you with the means for detecting and identifying memory leaks.

The primary tools for detecting memory leaks are the debugger and the C Run-Time Libraries (CRT) debug heap functions.

To enable the debug heap functions, include the following statements in your program:

#define _CRTDBG_MAP_ALLOC
#include <stdlib.h>
#include <crtdbg.h>

For the CRT functions to work correctly, the #include statements must follow the order shown here.

Including crtdbg.h maps the malloc and the free functions to their debug versions, _malloc_dbg and free, which track memory allocation and deallocation. This mapping occurs only in debug builds, which have_DEBUG. Release builds use the ordinary malloc and free functions.

The #define statement maps a base version of the CRT heap functions to the corresponding debug version. If you omit the #define statement, the memory leak dump will be less detailed.

After you have enabled the debug heap functions by using these statements, you can place a call to _CrtDumpMemoryLeaks before an application exit point to display a memory-leak report when your application exits:

_CrtDumpMemoryLeaks();

If your application has multiple exits, you do not need to manually place a call to _CrtDumpMemoryLeaks at every exit point. A call to _CrtSetDbgFlag at the beginning of your application will cause an automatic call to _CrtDumpMemoryLeaks at each exit point. You must set the two bit fields shown here:

_CrtSetDbgFlag ( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );

By default, _CrtDumpMemoryLeaks outputs the memory-leak report to the Debug pane of the Output window. You can use _CrtSetReportMode to redirect the report to another location.

If you use a library, the library might reset the output to another location. In that case, you can set the output location back to the Output window, as shown here:

_CrtSetReportMode( _CRT_ERROR, _CRTDBG_MODE_DEBUG );

If your application does not define _CRTDBG_MAP_ALLOC_CrtDumpMemoryLeaks displays a memory-leak report that looks like this:

Detected memory leaks!
Dumping objects ->
{18} normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

If your application defines _CRTDBG_MAP_ALLOC, the memory-leak report looks like this:

Detected memory leaks!
Dumping objects ->
C:\PROGRAM FILES\VISUAL STUDIO\MyProjects\leaktest\leaktest.cpp(20) : {18} 
normal block at 0x00780E80, 64 bytes long.
 Data: <                > CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD CD
Object dump complete.

The difference is that the second report shows name of the file and the line number where the leaked memory is first allocated.

Whether you define _CRTDBG_MAP_ALLOC or not, the memory-leak report will display the following information:

  • The memory allocation number, which is 18 in this example

  • The block type, which is normal in this example.

  • The hexadecimal memory location, which is 0x00780E80 in this example.

  • The size of the block, 64 bytes in this example.

  • The first 16 bytes of data in the block, in hexadecimal form.

The memory-leak report identifies a block of memory as normal, client, or CRT. A normal block is ordinary memory allocated by your program. A client block is a special type of memory block used by MFC programs for objects that require a destructor. The MFC new operator creates either a normal block or a client block, as appropriate for the object being created. A CRT block is allocated by the CRT library for its own use. The CRT library handles the deallocation for these blocks. Therefore, it is unlikely you will see these in the memory leak report unless something is significantly wrong, for example, the CRT library is corrupted.

There are two other types of memory blocks that never appear in memory-leak reports. A free block is memory that has been released. That means it is not leaked, by definition. An ignore block is memory that you have explicitly marked to exclude it from the memory-leak report.

These techniques work for memory allocated using the standard CRT malloc function. If your program allocates memory using the C++ new operator, however, you need to redefine new if you want to see the file and line numbers in the memory-leak report. You can do that with a block of code that looks like this:

#ifdef _DEBUG
   #ifndef DBG_NEW
      #define DBG_NEW new ( _NORMAL_BLOCK , __FILE__ , __LINE__ )
      #define new DBG_NEW
   #endif
#endif  // _DEBUG

The memory allocation number tells you when a leaked memory block was allocated. A block with a memory allocation number of 18, for example, is the 18th block of memory allocated during the run of the application. The CRT report counts all memory-block allocations during the run. This includes allocations by the CRT library and other libraries such as MFC. Therefore, a block with a memory allocation number of 18 may not be the 18th memory block allocated by your code. Typically, it will not be.

You can use the allocation number to set a breakpoint on the memory allocation.

To set a memory-allocation breakpoint using the Watch window

  1. Set a breakpoint near the start of your application, and then start your application.

  2. When the application breaks at the breakpoint, the Watch window.

  3. In the Watch window, type _crtBreakAlloc in in the Name column.

    If you are using the multithreaded DLL version of the CRT library (the /MD option), include the context operator: {,,msvcr100d.dll}_crtBreakAlloc

  4. Press RETURN.

    The debugger evaluates the call and places the result in the Value column. This value will be –1 if you have not set any breakpoints on memory allocations.

  5. In the Value column, replace the value shown with the allocation number of the memory allocation where you want to break.

After you set a breakpoint on a memory-allocation number, you can continue to debug. Be careful to run the program under the same conditions as the previous run so that the memory-allocation order does not change. When your program breaks at the specified memory allocation, you can use the Call Stack window and other debugger windows to determine the conditions under which the memory was allocated. Then, you can continue execution to observe what happens to the object and determine why it is not correctly deallocated.

Setting a data breakpoint on the object might also be helpful. For more information, see How to: Set a Data Breakpoint (Native Only).

You can also set memory-allocation breakpoints in code. There are two ways to do this:

_crtBreakAlloc = 18;

or:

_CrtSetBreakAlloc(18);

Another technique for locating memory leaks involves taking snapshots of the application's memory state at key points. To take a snapshot of the memory state at a given point in your application, create a_CrtMemState structure and pass it to the _CrtMemCheckpoint function. This function fills in the structure with a snapshot of the current memory state:

_CrtMemState s1;
_CrtMemCheckpoint( &s1 );

_CrtMemCheckpoint fills in the structure with a snapshot of the current memory state.

To output the contents of a _CrtMemState structure, pass the structure to the _ CrtMemDumpStatistics function:

_CrtMemDumpStatistics( &s1 );

_ CrtMemDumpStatistics outputs a dump of memory state that looks like this:

0 bytes in 0 Free Blocks.
0 bytes in 0 Normal Blocks.
3071 bytes in 16 CRT Blocks.
0 bytes in 0 Ignore Blocks.
0 bytes in 0 Client Blocks.
Largest number used: 3071 bytes.
Total allocations: 3764 bytes.

To determine whether a memory leak has occurred in a section of code, you can take snapshots of the memory state before and after the section, and then use _ CrtMemDifference to compare the two states:

_CrtMemCheckpoint( &s1 );
// memory allocations take place here
_CrtMemCheckpoint( &s2 );

if ( _CrtMemDifference( &s3, &s1, &s2) )
   _CrtMemDumpStatistics( &s3 );

_CrtMemDifference compares the memory states s1 and s2 and returns a result in (s3) that is the difference of s1 and s2.

One technique for finding memory leaks begins by placing _CrtMemCheckpoint calls at the beginning and end of your application, then using _CrtMemDifference to compare the results. If _CrtMemDifferenceshows a memory leak, you can add more _CrtMemCheckpoint calls to divide your program using a binary search until you have isolated the source of the leak.

In some cases, _CrtDumpMemoryLeaks can give false indications of memory leaks. This might occur if you use a library that marks internal allocations as _NORMAL_BLOCKs instead of _CRT_BLOCKs or_CLIENT_BLOCKs. In that case, _CrtDumpMemoryLeaks is unable to tell the difference between user allocations and internal library allocations. If the global destructors for the library allocations run after the point where you call _CrtDumpMemoryLeaks, every internal library allocation is reported as a memory leak. Older versions of the Standard Template Library, earlier than Visual Studio .NET, caused_CrtDumpMemoryLeaks to report such false positives, but this has been fixed in recent releases.

Did you find this helpful?   
Community Content  Add
Annotations  FAQ
setting breakpoint so _crtBreakAlloc works

Setting a breakpoint at the earliest point in our app deosn't work.

We needed to set in crt code as in the blog:
http://rdaemons.blogspot.co.uk/2011/03/visual-c-2010-detecting-memory-leaks.html

C:\Program Files\Microsoft Visual Studio 10.0\VC\crt\src\crt0dat.c
_initterm_e() function

static STL objects still reported as leaks
$0(trying to edit my previous entry just crashes the javascript on the page, so I'm reposting)$0 $0Enter comment here.Contrary to the documentation's assertion that the STL library was fixed, _CrtDumpMemoryLeaks  does continue to report false leaks.  You get false leaks on STL objects if they are declared static: $0 $0 $0static std::string g_myString;$0 $0 $0or part of a class:$0 $0$0 $0
class foo
{
public:
static std::string m_myString;
}
$0 $0$0 $0Both of these lines will report a leak using the _CrtDumpMemoryLeaks functionality.  I've filed a bug for this:$0 $0https://connect.microsoft.com/VisualStudio/feedback/details/697181/crt-memory-leak-detection-routines-still-report-statically-allocated-stl-objects-as-leaks#tabs$0 $0$0 $0$0
static STL objects still reported as leaks
Contrary to the documentation's assertion that the STL library was fixed so that   _CrtDumpMemoryLeaks  does not continue to report false leaks; you can still get false leak reports on STL objects if they are declared static: $0static std::string g_myString;$0 $0$0 $0 $0or part of a class$0 $0class foo$0 $0{$0 $0public:$0 $0static std::string m_myString;$0 $0}$0 $0$0 $0 $0Both of these lines will report a leak using the  _CrtDumpMemoryLeaks functionality.  I've filed a bug for this:$0  https://connect.microsoft.com/VisualStudio/feedback/d etails/697181/crt-memory-leak-detection-routines-still-report-statically-allocated-stl-objects-as-leaks#tabs$0
{,,msvcr100d.dll_crtBreakAlloc}
In Visual Studio 2010 with toolset set to v100, and with the /MDd, then you will need to use this, instead of the {,,msvcr100d.dll}_crtBreakAlloc like the document mentioned like it in v90 toolset.
http://social.msdn.microsoft.com/Forums/en-US/vsdebug/thread/544a848b-ccd7-43c0-89be-4bca09f7850e
For the screenshot you can ref my post in this thread.
(int*){,,msvcr100d.dll}__crtBreakAlloc
Two underlines between the "}" and crtBreakAlloc, rather than only one.
C++ using NEW operator
When using C++ you need to define _CRTDBG_MAP_ALLOC_NEW in addition to _CRTDBG_MAP_ALLOC in order to get new operators to be registered.

This fixes the file issue where the leaked lines are listed as the memory allocation number and block / memory addresses of the leaked line.

#define _CRTDBG_MAP_ALLOC
#define _CRTDBG_MAP_ALLOC_NEW

If you look in <crtdbg.h> 

#if defined(_CRTDBG_MAP_ALLOC) && defined(_CRTDBG_MAP_ALLOC_NEW)
/* We keep these inlines for back compatibility only;
 * the operator new defined in the debug libraries already calls _malloc_dbg,
 * thus enabling the debug heap allocation functionalities.
 *
 * These inlines do not add any information, due that __FILE__ is expanded
 * to "crtdbg.h", which is not very helpful to the user.
 * 
 * The user will need to define _CRTDBG_MAP_ALLOC_NEW in addition to
 * _CRTDBG_MAP_ALLOC to enable these inlines.
 */

You can see this NEW is required to get it working properly for C++ new / delete.
Advertisement
1. Are there any memory errors in the following programs? If so, list all of them. Assume that the user enters in correct input, and that the sizes entered are at least one. Write your solution in a text or Word file and submit it below. void main() { char *str, *input; int *ilist; int i, size1, size2; printf("Number of letters in word: "); scanf("%d", &size1;); /* user inputs an integer */ printf("Number of integers: "); scanf("%d", &size2;); /* user inputs an integer */ str = (char *) malloc(size1); ilist = (int *) malloc(size2); printf("Word: "); scanf("%s", str); /* user inputs a string */ for(i = 0; i < size2; i++) { printf("Number %d of %d: ", i + 1, size2); scanf("%d", ilist + i); /* user inputs an integer */ } } 2. Are there any memory errors in the following program? If so, list all of them. Write your solution in a text or Word file and submit it below. /* return 1 if str is "1", 0 otherwise */ int checkIf1(char *str) { char *newstr = malloc(strlen(str) + 1); strcpy(newstr, str); /* set newstr to str */ if (strcmp(newstr, "1") == 0) { /* newstr is "1" */ return 1; } free(newstr); return 0; } void main() { char *strArr[4] = {"1", "2", "3", "4"}; int i; for(i = 0; i < 4; i++) { printf("%d\n", checkIf1(strArr[i])); } } 3. Are there any memory errors in the following program? If so, list all of them. Write your solution in a text or Word file and submit it below. struct data { char *str1, *str2; }; /* returns two strings concatenated if they are not the same, NULL otherwise */ char *mergeSingleIfDifferent(char *s1, char *s2) { char *str = (char *) malloc(strlen(s1) + strlen(s2) + 1); if (strcmp(s1, s2) == 0) { /* strings are equal */ str = NULL; } else { strcpy(str, s1); strcat(str, s2); } return str; } /* copies merged strings (or NULL) into array of strings passed in (results) */ void mergeArrayIfDifferent(char *results[], char *strA1[], char *strA2[], int size) { int i; for(i = 0; i < size; i++) { results[i] = mergeSingleIfDifferent(strA1[i], strA2[i]); } } void printAndFree(int c, char *str) { if (str != NULL) { printf("%d: %s\n", c, str); free(str); } } void main() { char *strArr1[8] = {"1", "2", "3", "4", "5", "6", "7", "8"}; char *strArr2[8] = {"a", "2", "c", "4", "e", "6", "g", "8"}; char *results[8]; int i; mergeArrayIfDifferent(results, strArr1, strArr2, 8); for(i = 0; i < 8; i++) { printAndFree(i, results); } }
### 非零返回值的顺序逻辑 在编程中,非零返回值通常用于指示函数执行的结果状态。如果返回值为非零,则表示操作成功或特定条件满足;而零可能代表失败或其他特殊情况。以下是关于如何实现和理解这种逻辑的一些关键点。 #### 使用断言验证非零返回值 在硬件描述语言(HDL)中,例如Verilog中的测试平台代码片段[^1]展示了通过`assert`语句来验证某些条件下变量是否具有预期的非零值。此方法可以扩展到其他场景: ```verilog initial begin input1 = 1; @(posedge clk); @(negedge clk); assert(output1 != 0) else $error("Output is zero when expected non-zero"); end ``` 上述代码确保 `output1` 的值不等于零,否则会触发错误消息并停止仿真过程。 #### JavaScript 中处理数组过滤后的非零结果 对于高级脚本语言如JavaScript,在数据流管道中也可以应用类似的思路。下面的例子说明了如何筛选偶数并将它们乘以十之后求和得到最终结果[^2]: ```javascript const result = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] .filter(n => n % 2 === 0) .map(a => a * 10) .reduce((a, b) => a + b); if(result !== 0){ console.log(`Non-Zero Result: ${result}`); } else { throw new Error('Unexpected Zero Value'); } ``` 这里我们不仅实现了功能需求还加入了简单的异常捕获机制以防万一计算过程中出现了意外情况下的零值输出。 #### 处理未定义与非零判断的关系 当涉及到动态类型的环境比如JavaScript时,“undefined”的概念变得尤为重要因为它直接影响着程序的行为模式以及潜在的风险控制措施[^3]。考虑如下情形: ```javascript let myVar; function checkValue(val){ if(typeof val === 'undefined' || val === null ){ return false; } return !!val; // Convert any truthy value into true and falsy ones to false. } console.log(checkValue(myVar)); // Outputs False because it's undefined. myVar = 0; console.log(checkValue(myVar)); // Still outputs False since we treat both as invalid states here. myVar = -5; console.log(checkValue(myVar)); // Now returns True indicating valid non-zero condition met. ``` 在这个例子当中,即使输入的是负数(-5),只要它不是null或者undefined就被认为是一个有效的“non-zero”状态被接受下来继续后续流程。 ### 结论 综上所述,无论是低级硬件模拟还是高层软件开发领域里都存在着针对不同上下文中定义好的规则去判定某个表达式的取值范围从而决定下一步动作走向这样的通用原则。具体实现方式取决于所使用的工具集及其特性支持程度等因素影响较大。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值