我是Windows平台上的c++程序员。我使用的是Visual Studio 2008。
我通常会在代码中出现内存泄漏。
通常我通过检查代码来发现内存泄漏,但这很麻烦,而且并不总是一种好方法。
因为我买不起付费的内存泄漏检测工具,所以我想让你们建议避免内存泄漏的最佳方法。
我想知道如何程序员可以找到内存泄漏。 是否应该遵循某种标准或过程来确保程序中没有内存泄漏?
我是Windows平台上的c++程序员。我使用的是Visual Studio 2008。
我通常会在代码中出现内存泄漏。
通常我通过检查代码来发现内存泄漏,但这很麻烦,而且并不总是一种好方法。
因为我买不起付费的内存泄漏检测工具,所以我想让你们建议避免内存泄漏的最佳方法。
我想知道如何程序员可以找到内存泄漏。 是否应该遵循某种标准或过程来确保程序中没有内存泄漏?
当前回答
确保成功释放了所有堆内存。如果您从未在堆上分配内存,则不需要这样做。如果你这样做,计算你malloc内存的次数,并计算你释放内存的次数。
其他回答
在应用程序代码中不应该使用“new”或“delete”。相反,应该创建一个使用管理器/工作人员习惯用法的新类型,其中管理器类分配和释放内存,并将所有其他操作转发给工作人员对象。
不幸的是,这比它应该做的要多,因为c++没有“operator .”的重载。如果存在多态,则工作量更大。
但是这样做是值得的,因为这样您就不必担心内存泄漏,这意味着您甚至不需要寻找它们。
回答你问题的第二部分,
是否有任何标准或程序可以确保程序中没有内存泄漏。
是的,有。这是C和c++的主要区别之一。
在c++中,永远不要在用户代码中调用new或delete。RAII是一种非常常用的技术,它在很大程度上解决了资源管理问题。程序中的每一个资源(资源是任何需要获取,然后释放的东西:文件句柄,网络套接字,数据库连接,但也包括普通内存分配,在某些情况下,对API调用(BeginX()/EndX(), LockY(), UnlockY()))都应该包装在一个类中,其中:
构造函数获取资源(如果资源是内存分配,则调用new) 析构函数释放资源, 复制和赋值要么被阻止(通过将复制构造函数和赋值操作符设置为私有),要么被实现为正确工作(例如通过克隆底层资源)
然后,该类在本地、堆栈上或作为类成员实例化,而不是通过调用new和存储指针来实例化。
You often don't need to define these classes yourself. The standard library containers behave in this way as well, so that any object stored into a std::vector gets freed when the vector is destroyed. So again, don't store a pointer into the container (which would require you to call new and delete), but rather the object itself (which gives you memory management for free). Likewise, smart pointer classes can be used to easily wrap objects that just have to be allocated with new, and control their lifetimes.
这意味着当对象超出作用域时,它将被自动销毁,并释放和清理它的资源。
如果在整个代码中始终这样做,就不会有任何内存泄漏。所有可能泄露的内容都绑定到析构函数,该析构函数保证在控件离开声明对象的作用域时被调用。
AddressSanitizer (ASan)是一种快速的内存错误检测器。 它可以发现C/ c++程序中的use-after-free和{heap,stack,global}-buffer溢出错误。它发现:
在free之后使用(悬空指针解引用) 堆缓冲区溢出 堆栈缓冲区溢出 全局缓冲区溢出 退货后使用 初始化顺序错误
这个工具很快。仪器程序的平均速度为~2倍。
运行“Valgrind”可以:
1)帮助识别内存泄漏-显示您有多少内存泄漏,并指出代码中泄漏内存分配的行。
2)指出错误的释放内存的尝试(例如不正确的delete调用)
“Valgrind”使用说明
1)在这里获得valgrind。
2)使用-g标志编译代码
3)在shell中运行:
valgrind --leak-check=yes myprog arg1 arg2
其中"myprog"是你编译的程序,arg1, arg2是你程序的参数。
4)结果是一个调用malloc/new的列表,没有后续调用free delete。
例如:
==4230== at 0x1B977DD0: malloc (vg_replace_malloc.c:136)
==4230== by 0x804990F: main (example.c:6)
告诉您在哪一行(未释放的)调用了malloc。
正如其他人指出的那样,确保对于每个新的/malloc调用,都有一个后续的delete/free调用。
您可以在代码中使用一些技术来检测内存泄漏。最常见和最简单的检测方法是,定义一个宏(比如DEBUG_NEW),并使用它与预定义的宏(如__FILE__和__LINE__)一起定位代码中的内存泄漏。这些预定义的宏告诉您内存泄漏的文件号和行号。
DEBUG_NEW只是一个宏,通常定义为:
#define DEBUG_NEW new(__FILE__, __LINE__)
#define new DEBUG_NEW
因此,无论在哪里使用new,它都可以跟踪文件和行号,这可以用来定位程序中的内存泄漏。
而__FILE__, __LINE__是预定义的宏,它们分别计算你使用它们的文件名和行号!
阅读下面的文章,它解释了使用DEBUG_NEW和其他有趣的宏的技术,非常漂亮:
一个跨平台的内存泄漏检测器
从Wikpedia,
Debug_new refers to a technique in C++ to overload and/or redefine operator new and operator delete in order to intercept the memory allocation and deallocation calls, and thus debug a program for memory usage. It often involves defining a macro named DEBUG_NEW, and makes new become something like new(_FILE_, _LINE_) to record the file/line information on allocation. Microsoft Visual C++ uses this technique in its Microsoft Foundation Classes. There are some ways to extend this method to avoid using macro redefinition while still able to display the file/line information on some platforms. There are many inherent limitations to this method. It applies only to C++, and cannot catch memory leaks by C functions like malloc. However, it can be very simple to use and also very fast, when compared to some more complete memory debugger solutions.