使用Visual Studio 2013在C中查找内存泄漏

使用Visual Studio 2013在C中查找内存泄漏,c,memory,visual-studio-2013,memory-leaks,memory-profiling,C,Memory,Visual Studio 2013,Memory Leaks,Memory Profiling,我正在使用Visual Studio 2013,正在学习C编程课程,我们开始讨论内存错误,特别是内存泄漏,以及如何在Linux上使用Valgrind检测它们 我想知道是否有一种方法可以使用VS2013检测此类内存泄漏。我尝试在线搜索,但它只会导致大量文章和博客以及msdn帖子和博客,其中包含大量单词,如转储文件、分析文件等,这很奇怪,因为: 它听起来如此复杂、复杂和不直观,实际上很难理解 2这很奇怪的主要原因是VS是最先进的IDE,微软在这方面花了很多钱,但据我所知,似乎没有简单的方法可以使用V

我正在使用Visual Studio 2013,正在学习C编程课程,我们开始讨论内存错误,特别是内存泄漏,以及如何在Linux上使用Valgrind检测它们

我想知道是否有一种方法可以使用VS2013检测此类内存泄漏。我尝试在线搜索,但它只会导致大量文章和博客以及msdn帖子和博客,其中包含大量单词,如转储文件、分析文件等,这很奇怪,因为:

它听起来如此复杂、复杂和不直观,实际上很难理解

2这很奇怪的主要原因是VS是最先进的IDE,微软在这方面花了很多钱,但据我所知,似乎没有简单的方法可以使用VS来检测内存泄漏-当然没有像Valgrind这样简单的方法,我只需要编译程序并运行命令 valgrind-泄漏检查=是程序名

它简单地向我打印出它认为内存泄漏的所有位置,并描述了错误,比如在分配malloc后没有释放内存,因此在程序完成后有死内存,或者访问超出数组边界的内存


因此,我的问题是如何使用VS 2013,以获得相同的结果,并首先在高层发现程序中是否存在内存泄漏,第二,以一种简单的方式检测这些泄漏的位置-最好不涉及转储文件,因为我不知道如何在VS中使用它们。

我提供的答案不可能是完美的,因为我详尽地解释了VS2013等的所有功能。提供了寻找C/C++堆hickups可能是一本畅销书。就这一点而言,它不是很薄

首先,我将不介绍的内容:

h-语义注释,如果提供,也可由MS工具使用。 并非所有的Crt*功能都可用。只有少数人提出了这个想法。 应用程序设计人员可能需要向其设计中添加的其他步骤,以实现生产质量代码库。 话虽如此,这里有一段带注释的代码,其中包含各种各样的bug,期待着一场反对票的狂欢,因为这就是上次我故意展示bug代码时发生的事情。。。。每个bug都附有注释,说明如何通过VS2013提供的功能检测到它。在运行时、编译时或静态代码分析时

编译时错误部分放在注释中,顺便说一句

#include "stdafx.h"
#include <crtdbg.h>
#include <malloc.h>
#include <cstdint>
#include <cstdlib>

// This small helper class shows the _Crt functions (some of them)
// and keeps the other code less cluttered. 
// Note: This is NOT what you should do in production code,
// as all those _Crt functions disappear in a release build,
// but this class does not disappear...
class HeapNeutralSection
{
    _CrtMemState m_start;

public:
    HeapNeutralSection()
    {
        _CrtMemCheckpoint(&m_start);
    }

    ~HeapNeutralSection()
    {
        _CrtMemState now;
        _CrtMemState delta;
        _CrtMemCheckpoint(&now);
        if (_CrtMemDifference(&delta, &m_start, &now))
        {
            // This code section is not heap neutral!
            _CrtMemDumpStatistics(&delta);
            _CrtDumpMemoryLeaks();
            _ASSERTE(false);

        }
    }
};


static void DoubleAllocationBug()
{
    {
        HeapNeutralSection hns;

        uint32_t *rogue = (uint32_t*)malloc(sizeof(uint32_t));
        if (NULL != rogue)
        {
            *rogue = 42; // Static Analysis without the NULL check: Dereferencing null pointer.
        }
        rogue = (uint32_t*)malloc(sizeof(uint32_t));
        free(rogue);
        // detected in destructor of HeapNeutralSection.
    }
}

static void UninitializedPointerAccessBug()
{
//  uint32_t *rogue;
//  *rogue = 42; // C4700: uninitialized local variable 'rogue' used.
}

static void LeakBug()
{
    {
        HeapNeutralSection hns;

        uint32_t *rogue = (uint32_t*)malloc(sizeof(uint32_t));
        if (NULL != rogue)
        {
            *rogue = 42; // Static Analysis without the NULL check: Dereferencing null pointer.
        }
    }
}

static void InvalidPointerBug()
{
    // Not sure if the C-compiler also finds this... one more reason to program C with C++ compiler ;)
    // uint32_t *rogue = 234; // C2440: 'initalizing': cannot convert from 'int' to 'uint32_t *'

}

static void WriteOutOfRangeBug()
{
    {
        HeapNeutralSection hns;
        uint32_t * rogue = (uint32_t*)malloc(sizeof(uint32_t));
        if (NULL != rogue)
        {
            rogue[1] = 42; // Static analysis: warning C6200: Index '1' is out of valid index range '0' to '0' for non-stack buffer 'rogue'.
            rogue[2] = 43; // Static analysis: warning C6200: Index '2' is out of valid index range '0' to '0' for non-stack buffer 'rogue'.
            // warning C6386: Buffer overrun while writing to 'rogue':  the writable size is '4' bytes, but '8' bytes might be written.
        }
        free(rogue); // We corrupted heap before. Next malloc/free should trigger a report.
        /*
        HEAP[ListAppend.exe]: Heap block at 0076CF20 modified at 0076CF50 past requested size of 28
        ListAppend.exe has triggered a breakpoint.
        */
    }
}

static void AccessAlreadyFreedMemoryBug()
{
    {
        HeapNeutralSection hns;
        uint32_t * rogue = (uint32_t*)malloc(sizeof(uint32_t));
        free(rogue);

        *rogue = 42; // Static analysis: warning C6001: Using uninitialized memory 'rogue'.
    }
}

int _tmain(int argc, _TCHAR* argv[])
{
    // checks heap integrity each time a heap allocation is caused. Slow but useful.
    _CrtSetDbgFlag(_CRTDBG_CHECK_ALWAYS_DF); 

    AccessAlreadyFreedMemoryBug();
    WriteOutOfRangeBug();
    UninitializedPointerAccessBug();
    DoubleAllocationBug();

    // _CrtDumpMemoryLeaks();
    return 0;
}
最后同样重要的是,在Windows CE和DDK中,可能在平台SDK中,曾经有两个静态代码检查器prefast和prefix。但也许它们现在已经过时了。 此外,还有一些MS研究项目,超越了sal.h,例如:
,这有助于发现并发错误等。

实际上,根据计算方式,可以检测内存泄漏的级别分为2级或3级。首先,即使使用免费社区版,也可以使用VS2013内置的静态代码分析器。第二,您可以进行调试构建并使用运行时检查,以使您受益。最后,windows API中有一组函数,允许检查堆并找出是否存在损坏的堆、悬空堆对象等。。。也许你最好的防泄漏武器是切换到C++,而不是直接使用直接内存分配来编写代码。使用第三方工具:VLD、DeleKek等等。实际上,这些工具与正常堆诊断功能一样,将结果封装在一个糖果UI中。为什么要使用工具来替换6-10行插装代码?@user2225104我有几件事想让你澄清一下/eleborate关于你的第一条评论请记住,我到目前为止还没有做过内存分析,所以我不熟悉这些工具:1 VS中的静态代码分析器是什么,如何使用它在UI中的位置和它是做什么的?例如,它能表明我有悬挂的物体吗?2使用运行时检查是什么意思-您是指一步一步地运行代码吗?无法定位内存泄漏3您在谈论什么函数和API,更实际的是-我如何使用它们,在哪里使用它们?