内存泄漏,无法找到源

时间:2012-11-23 12:19:14

标签: c++ memory-leaks mfc kinect

我有很大的内存泄漏,我需要一些帮助才能找到它的来源。首先,关于代码的一些理论:

这是一个Kinect项目。它是在MS Visual Studio 2012中构建的MFC项目,它使用Direct2D将图像放在屏幕上。 当我从Kinect 1切换到Kinect 2时会发生此问题。然后重建除“主”对象之外的每个对象(解构/释放并置为NULL(如果指针))。 这包括:

  • 所有Direct2D对象(工厂,Rendertargets,位图,画笔,所有内容)
  • 带线程的Kinect facetracker
  • 带线程的kinect对象。

对于每个新关键字,我在析构函数中使用了delete关键字(所以我没有做任何事情来破坏那些没有用new初始化的指针)。我关闭了所有线程处理程序并将它们设置为NULL。

现在我有内存泄漏,我需要一些帮助才能找到它。我开始使用MS MFC tools

初始化后我有一些输出:

Dumping objects ->
{402} normal block at 0x1531E8F0, 28 bytes long.
 Data: <<       @       > 3C 07 06 00 F0 00 00 00 40 01 00 00 00 05 00 00 
{401} normal block at 0x152F6CD8, 96 bytes long.
 Data: <    >           > 00 CD CD CD 3E 07 06 00 D0 04 00 00 D8 17 00 00 
{400} normal block at 0x03EA0040, 1229064 bytes long.
 Data: <R            E, > 52 07 06 00 B8 A9 13 00 D0 87 D0 00 18 45 2C 15 
{396} normal block at 0x152C9EA0, 20 bytes long.
 Data: <                > 80 F9 89 00 01 00 00 00 01 00 00 00 01 00 00 00 
c:\users\work\documents\github\kinectmain\testmfc\main.cpp(148) : {305} client block at 0x152CF618, subtype c0, 8 bytes long.
a CFont object at $152CF618, 8 bytes long
{295} normal block at 0x152CFC20, 24 bytes long.
 Data: <X   ( , X       > 58 07 CC 00 28 F8 2C 15 58 07 CC 00 00 00 CD CD 
{284} normal block at 0x152CF828, 24 bytes long.
 Data: <X   X     ,     > 58 07 CC 00 58 07 CC 00 20 FC 2C 15 01 00 CD CD 
{206} normal block at 0x00CD0588, 12 bytes long.
 Data: <    @       > B0 04 CD 00 40 05 CD 00 B8 A9 13 00 
{205} normal block at 0x00CD0540, 12 bytes long.
 Data: <            > 88 05 CD 00 B0 04 CD 00 18 BE 13 00 
{204} normal block at 0x00CD04F8, 8 bytes long.
 Data: <        > EC F3 89 00 00 00 00 00 
{203} normal block at 0x00CD04B0, 12 bytes long.
 Data: <@           > 40 05 CD 00 88 05 CD 00 CD CD CD CD 
{202} normal block at 0x00CD0468, 12 bytes long.
 Data: <    H       > 08 FE CC 00 48 A5 CC 00 18 BE 13 00 
{201} normal block at 0x00CCFE08, 12 bytes long.
 Data: <H   h       > 48 A5 CC 00 68 04 CD 00 B8 A9 13 00 
{200} normal block at 0x00CCA590, 8 bytes long.
 Data: <        > FC A4 CC 00 00 00 00 00 
{199} normal block at 0x00CCA548, 12 bytes long.
 Data: <h           > 68 04 CD 00 08 FE CC 00 CD CD CD CD 
c:\users\work\documents\github\kinectmain\testmfc\main.cpp(163) : {198} normal block at 0x00CCA4F8, 16 bytes long.
 Data: <R       H       > 52 07 06 00 90 A5 CC 00 48 A5 CC 00 02 00 00 00 
{188} normal block at 0x00CC07B0, 8 bytes long.
 Data: <        > 9C FB A1 00 00 00 00 00 
{187} normal block at 0x00CC0758, 24 bytes long.
 Data: <( , ( ,   ,     > 28 F8 2C 15 28 F8 2C 15 20 FC 2C 15 01 01 CD CD 
Object dump complete.
0 bytes in 0 Free Blocks.
1229392 bytes in 17 Normal Blocks.
13498 bytes in 73 CRT Blocks.
0 bytes in 0 Ignore Blocks.
8 bytes in 1 Client Blocks.
Largest number used: 1245916 bytes.
Total allocations: 2504946 bytes.

在kinect开关之后:

Dumping objects ->
{961} normal block at 0x1531E8F0, 28 bytes long.
 Data: <<       @       > 3C 07 06 00 F0 00 00 00 40 01 00 00 00 05 00 00 
{960} normal block at 0x1534A658, 96 bytes long.
 Data: <    >   p       > 00 CD CD CD 3E 07 06 00 70 05 00 00 A8 15 00 00 
{959} normal block at 0x03EA0040, 1229064 bytes long.
 Data: <R         ,   4 > 52 07 06 00 18 BE 13 00 90 F1 2C 15 98 9B 34 15 
{956} normal block at 0x152CBFD0, 20 bytes long.
 Data: <                > 80 F9 89 00 01 00 00 00 01 00 00 00 01 00 00 00 
c:\users\work\documents\github\kinectmain\testmfc\main.cpp(148) : {305} client block at 0x152CF618, subtype c0, 8 bytes long.
a CFont object at $152CF618, 8 bytes long
{295} normal block at 0x152CFC20, 24 bytes long.
 Data: <X   ( , X       > 58 07 CC 00 28 F8 2C 15 58 07 CC 00 00 00 CD CD 
{284} normal block at 0x152CF828, 24 bytes long.
 Data: <X   X     ,     > 58 07 CC 00 58 07 CC 00 20 FC 2C 15 01 00 CD CD 
{206} normal block at 0x00CD0588, 12 bytes long.
 Data: <    @       > B0 04 CD 00 40 05 CD 00 B8 A9 13 00 
{205} normal block at 0x00CD0540, 12 bytes long.
 Data: <            > 88 05 CD 00 B0 04 CD 00 18 BE 13 00 
{204} normal block at 0x00CD04F8, 8 bytes long.
 Data: <        > EC F3 89 00 00 00 00 00 
{203} normal block at 0x00CD04B0, 12 bytes long.
 Data: <@           > 40 05 CD 00 88 05 CD 00 CD CD CD CD 
{202} normal block at 0x00CD0468, 12 bytes long.
 Data: <    H       > 08 FE CC 00 48 A5 CC 00 18 BE 13 00 
{201} normal block at 0x00CCFE08, 12 bytes long.
 Data: <H   h       > 48 A5 CC 00 68 04 CD 00 B8 A9 13 00 
{200} normal block at 0x00CCA590, 8 bytes long.
 Data: <        > FC A4 CC 00 00 00 00 00 
{199} normal block at 0x00CCA548, 12 bytes long.
 Data: <h           > 68 04 CD 00 08 FE CC 00 CD CD CD CD 
c:\users\work\documents\github\kinectmain\testmfc\main.cpp(163) : {198} normal block at 0x00CCA4F8, 16 bytes long.
 Data: <R       H       > 52 07 06 00 90 A5 CC 00 48 A5 CC 00 02 00 00 00 
{188} normal block at 0x00CC07B0, 8 bytes long.
 Data: <        > 9C FB A1 00 00 00 00 00 
{187} normal block at 0x00CC0758, 24 bytes long.
 Data: <( , ( ,   ,     > 28 F8 2C 15 28 F8 2C 15 20 FC 2C 15 01 01 CD CD 
Object dump complete.
0 bytes in 0 Free Blocks.
1229392 bytes in 17 Normal Blocks.
13498 bytes in 73 CRT Blocks.
0 bytes in 0 Ignore Blocks.
8 bytes in 1 Client Blocks.
Largest number used: 1245916 bytes.
Total allocations: 3742634 bytes.

因此总分配从2504946字节增加到3742634字节,但没有其他变化。

对于每个开关,我都会收到以下错误:

calling DestroyWindow in CWnd::~CWnd; OnDestroy or PostNcDestroy in derived class will not be called.

即使我没有在程序关闭之前调用destroyWindow。

完整的源代码可以在这里找到:https://github.com/ProjectPrague/KinectMain/tree/Bugfixing-Branch

关于可能是什么原因或者我可以用什么工具找到原因的任何提示,建议或提示都会很棒。

2 个答案:

答案 0 :(得分:6)

{}括号中的数字是分配订单号。如果你的程序是完全确定的并且每次都完全相同,那么这些数字应该从一次运行到下一次运行保持不变。

在这种情况下你可以使用这个技巧。将以下代码添加到主函数的顶部:

long lBreakAlloc = 0;
if ( lBreakAlloc > 0 )
{
    _CrtSetBreakAlloc( lBreakAlloc );
}

然后在if语句上设置断点并启动程序。当它停在if时,更改lBreakAlloc的值以匹配第一个泄漏内存块的分配顺序号,然后让程序继续。

当它到达分配那块内存的点时,嘿presto!它将在调试器中停止,您可以确切地看到未释放哪个分配。

答案 1 :(得分:2)

unInit类中的Kinect方法肯定是内存泄漏的来源。每个字段都设置为null,而不先删除指向的对象(如果有)。我还发现了至少一个返回指向新对象(selectKinect)的指针的方法。除非您仔细管理这些对象,否则它们也将成为内存泄漏的来源。

您可能希望考虑使用库来帮助您进行内存管理。 Boost的共享指针非常有用。

#include <boost/shared_ptr.hpp>

using boost::shared_ptr;

shared_ptr<Kinect> kinect(new Kinnect);

kinect->SomeMethodOnKinnect();

Boost的共享指针使用引用计数来知道何时删除对象,并在调用shared_ptr构造函数和析构函数时自动更新对象的引用计数。

你真的需要用精细的梳子来检查你的代码,因为你的代码似乎充满了内存泄漏。下面的代码说它应该删除指针,但只是将它们设置为NULL。

//Should delete a pointer and set it to NULL
void FaceTracking::Release()
{
    faceTrackingResult = NULL;
    nuiPresent = NULL;
    ColorBuffer = NULL;
    DepthBuffer = NULL;
}