我想使用标准实用程序在应用程序中找到内存泄漏。以前,我使用了自己的内存分配器,但是其他人(是的,您的Alienfluid)建议使用Microsoft的应用程序验证仪,但我似乎无法让它报告我的泄漏。我有以下简单应用程序:

#include <iostream>
#include <conio.h>

class X
   {
   public:
      X::X() : m_value(123) {}
   private:
      int m_value;
   };

void main()
{
X *p1 = 0;
X *p2 = 0;
X *p3 = 0;

p1 = new X();
p2 = new X();
p3 = new X();
delete p1;
delete p3;
}

该测试显然包含内存泄漏:P2是新的,但未删除。

我使用以下命令行构建可执行文件:

cl /c /EHsc /Zi /Od /MDd test.cpp
link /debug test.obj

我下载了应用程序验证仪(4.0.0665)并启用了所有检查。

如果我现在运行测试应用程序,我可以在应用程序验证器中看到它的日志,但是我看不到内存泄漏。

问题:

  • 应用程序验证者为什么不报告泄漏?
  • 还是应用程序验证者不是真正打算找到泄漏的?
  • 如果不是哪些其他工具可以在应用程序末尾清楚地报告泄漏(即,不是通过定期快照并进行比较,因为在应用1GB或更多的应用程序中无法进行比较),包括该应用程序的调用堆栈分配的地方(因此,CRT末尾的简单泄漏报告)

如果我找不到体面的实用程序,那么我仍然必须依靠自己的内存管理器(这很好)。

有帮助吗?

解决方案

CRT内存泄漏检测(无堆栈跟踪):

// debug_new.h
#pragma once

#include "crtdbg.h"

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

所有.cpp文件:

#include "debug_new.h"

...

// After all other include lines:
#ifdef _DEBUG
#define new DEBUG_NEW
#endif

...

在程序初始化代码中写一次:

_CrtSetDbgFlag( _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG) | _CRTDBG_LEAK_CHECK_DF);

在MFC中,所有这些已经在MFC标题中实现。您只需要确保每个CPP文件都包含以下行:

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

限制:这仅捕获“新的”内存泄漏,所有泄漏,由其他功能(如Malloc)引起的所有泄漏。

不要在.h文件的内部进行任何分配 - 它们将在没有源线的情况下打印,因为在所有#include行之后定义了debug_new。

其他提示

应用程序验证者仅在DLL中捕获泄漏。尝试在泄漏复选框中读取工具提示。这就是它的意思。

我觉得应用程序验证者特殊情况是出口路径,并且不会将其标记为泄漏 - 毕竟,整个过程堆都是免费的。

尝试编写另一个样本,在其中再次初始化相同的指针 - 基本上失去对先前分配的引用。当然应该标记。让我知道结果。

另外,相关器(如果您已启用了所有选项)也应捕获缓冲区的溢出,下垂,写入标记为RO等的堆栈位置。

来自软件验证的内存验证器将收集内存泄漏,并显示泄漏分配中的完整呼叫炉灶。虽然它是商业产品,但它有一个试用期,因此程序员可以尝试一下,看看是否值得对他们的价格。

最简单的解决方案是 首先不要写泄漏或缓冲区溢出 - 事件发生后发现它们确实是浪费努力。在我自己的代码中,多年来,我在这些领域的问题零。为什么?因为我使用C ++提供的机制来避免它们。例如:

X *p1 = 0;
p1 = new X();

应该:

shared_ptr <X>  p1 = new X();

而且您不再担心P1泄漏。更好的是,不要完全使用动态分配:

X x1;

对于缓冲区溢出,始终使用将在输入上生长的STD :: String之类的类型,或者如果它们不生长,则会检测到可能的溢出并警告您。

我不夸耀自己在避免记忆泄漏方面的能力 - 这些东西确实有效,并且可以让您继续进行调试的更加困难的任务 商业 代码的逻辑。

视觉泄漏探测器 (v2.2)比CRT调试库更有用,因为它将显示用于存储器分配的完整呼叫堆栈已导致泄漏。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top