使用Visual Studio在C++应用程序中查找内存泄漏问题

68

在Linux中,我一直使用valgrind来检查应用程序是否存在内存泄漏。在Windows中有没有类似的工具?能否通过Visual Studio 2010实现这一功能?


可能是Is there a good Valgrind substitute for Windows?的重复问题。 - Patrick
9个回答

85

Visual Studio 2019提供了一个不错的内存分析工具,可以在调试时交互式使用或在编程(无需调试)时使用。下面我将展示两种情况下的最小示例。

主要思路是在进程开始和结束时对堆进行快照,然后比较内存状态以检测潜在的内存泄漏。

交互式使用

创建以下main.cpp文件(在新控制台应用程序中):

#include <string.h>
int main()
{
 int a = 1;
 char* s = new char[17];
 strcpy_s(s,17,"stackoverflow_pb");
 char* ss = new char[14];
 strcpy_s(ss, 14,"stackoverflow");
 delete[] ss;
 return 0;
}

接下来:

  1. 在第一行 "int a..." 上设置一个断点
  2. 点击调试(Debug) > 窗口(Windows) > 显示诊断工具(Show Diagnostic Tools) 并选择内存使用情况(Memory Usage)
  3. 调试代码(F5),当断点被触发时,在内存使用情况摘要工具栏上点击 Take snapshot
  4. 走到最后一行 "return 0..." (step over (F10) 几次),并再次拍摄一个快照
  5. 在第二个快照中的内存使用情况选项卡上点击红色箭头
  6. 这将打开一个新的"快照"选项卡,允许您将此快照与第一个快照(或其他快照)进行比较,并检测内存泄漏。在这个例子中,变量 s (stackoverflow_pb)存在内存泄漏。您可以通过双击 "char[]" 对象找到它。

以上步骤的关键部分显示在以下图像中:

memory analysis interactively

通过编程实现

请用以下代码替换原来的代码:

#include <iostream>

#include "windows.h"
#define _CRTDBG_MAP_ALLOC //to get more details
#include <stdlib.h>  
#include <crtdbg.h>   //for malloc and free
int main()
{
    _CrtMemState sOld;
    _CrtMemState sNew;
    _CrtMemState sDiff;
    _CrtMemCheckpoint(&sOld); //take a snapshot
    char* s = new char[17];
    strcpy_s(s, 17, "stackoverflow_pb");
    char* ss = new char[14];
    strcpy_s(ss, 14, "stackoverflow");
    delete[] ss;
    _CrtMemCheckpoint(&sNew); //take a snapshot 
    if (_CrtMemDifference(&sDiff, &sOld, &sNew)) // if there is a difference
    {
        OutputDebugString(L"-----------_CrtMemDumpStatistics ---------");
        _CrtMemDumpStatistics(&sDiff);
        OutputDebugString(L"-----------_CrtMemDumpAllObjectsSince ---------");
        _CrtMemDumpAllObjectsSince(&sOld);
        OutputDebugString(L"-----------_CrtDumpMemoryLeaks ---------");
        _CrtDumpMemoryLeaks();
    }
    return 0;
}

它通过代码实现相同的功能,因此您可以将其集成到自动构建系统中,函数_CrtMemCheckpoint获取快照,_CrtMemDifference比较快照的内存状态,并在它们不同时返回true。

因为这是这种情况,它进入条件块并通过几个函数(请参见_CrtMemDumpStatistics_CrtMemDumpAllObjectsSince_CrtDumpMemoryLeaks - 后者不需要快照)打印有关泄漏的详细信息。

要查看输出,请在最后一行“return 0”处放置断点,按下F5并查看调试控制台。以下是输出:

enter image description here


要获取更多信息,请参见以下链接:


1
这很好。我们有没有办法检查以下几点:1.混合使用数组new[]和错误的delete,2.访问已释放的内存,3.其他破坏内存的方式,如越界访问等。4.访问未初始化的内存。 - Ayxan Haqverdili
1
抱歉,我不知道1、3和4的解决方法,但我会使用静态分析工具来解决。关于2(访问已释放的内存),您可以使用“_CRTDBG_DELAY_FREE_MEM_DF”标志(请参见上面链接中的“CRT debug Heap Files”)。 - Malick
1
/fsanitize=address现在可用于x64和x86,用于类似的内存问题。 AddressSanitizer - Ayxan Haqverdili
2
这太多工作了,超出了1000%。难道真的没有Windows版本的valgrind吗? - Roflcopter4
@Roflcopter4,不是很确定。你最好在Linux上使用Valgrind进行开发,并确保它足够可移植,可以在Windows上编译。 - Ayxan Haqverdili
显示剩余6条评论

13

你觉得使用Visual Leak Detector怎么样?虽然它不是内置的,但我认为它是最受欢迎的。


7
该项目已经转移到https://kinddragon.github.io/vld/,然后在2017年被放弃。 - anon
3
似乎仍然可以在VS 2019中使用,参见此处链接:https://dev59.com/brbna4cB1Zd3GeqPkPit - FourtyTwo

4

Dr. Memory 是一款内存监测工具,能够识别与内存相关的编程错误,如访问未初始化的内存、访问不可寻址的内存(包括超出分配堆单元以及堆下溢和上溢),访问已释放的内存、重复释放、内存泄漏以及(在 Windows 上)句柄泄漏、GDI API 使用错误以及访问未保留的线程局部存储插槽。

Dr. Memory 可以运行于 Windows、Linux、Mac 或 Android 上,对经过修改的应用程序二进制文件进行操作,支持通用 IA-32、AMD64 和 ARM 硬件。

Dr. Memory 基于 DynamoRIO 动态检测工具平台构建。


1
按照页面上的说明操作,我遇到了“Dr.Memory内部崩溃”的问题。有什么建议吗? - Ayxan Haqverdili
1
DrM在正常工作时非常出色,但像其他人发现的那样,2020年2月的2.3.0.1版本容易出现内部段错误。 - Nick

4

C++内存验证器 可以在使用Visual Studio、Delphi和其他编译器构建的本机Windows程序中查找内存和句柄泄漏。它快速且可以处理大量工作负载(一些用户在一次运行中跟踪数十亿个分配和释放)。

声明:我是C++内存验证器的设计师。我们构建它是因为当我们与SolidWorks R&D Ltd合作时,其他工具无法处理工作负载。


3

这个功能在社区版中也可用吗? - AntonK
它在我的VS 2017社区版中可用,不确定2015是否可用。 - Oleg Smirnov

3

Application Verifier 是一个用于检测本地(C或C++)应用程序中泄漏的好工具。您可以与Visual Studio 或 WinDbg一起使用它。除了内存泄漏外,还可以检查堆损坏、无效句柄使用等问题。与WinDbg (!analyze -v) 一起使用应用程序验证器可以提供良好的见解。


1
一种可靠的解决方案是使用Visual Studio的Address Sanitizer。这是一个跨平台/跨编译器的解决方案,因此您获得的知识将可转移到gcc和clang。该工具具有线程消毒和一般内存错误检测(使用后释放、双重释放、未初始化使用等),但泄漏检测是其强项之一。您需要使用Microsoft编译器的/fsanitize=address /Zi选项,但您可以参考第一个链接文章中如何将其纳入解决方案和更大项目(通过CMake配置或项目属性调整)。

0

您可以使用DevPartner工具在Visual Studio中查找C ++应用程序中的内存泄漏问题。


0
一个独立的工具(CLI),用于跟踪本地(C ++)内存泄漏。在发布模式下运行您的应用程序(应该可用PDB文件),并让它与之一起运行。它输出所有疑似调用堆栈及其相应的泄漏大小:
GitHub链接:C++内存泄漏检测器 for Windows

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接