1

大きなメモリリークがあり、それがどこから来ているのかを見つけるのに助けが必要です。まず、コードに関するいくつかの理論:

Kinectプロジェクトです。これはMSVisualStudio 2012でビルドされたMFCプロジェクトであり、Direct2Dを使用して画面に画像を配置します。この問題は、Kinect1からKinect2に切り替えるときに発生します。その後、「メイン」オブジェクトを除くすべてのオブジェクトが再構築されます(分解/解放され、NULL(ポインターの場合)になります)。これも:

  • すべてのDirect2Dオブジェクト(ファクトリ、Rendertargets、ビットマップ、ブラシ、すべて)
  • スレッド付きのKinectフェイストラッカー
  • スレッドを持つkinectオブジェクト。

新しいキーワードごとに、デストラクタでdeleteキーワードを使用しました(したがって、newで初期化されていないポインタを破棄するために何もしませんでした)。すべてのスレッドハンドラーを閉じて、それらをNULLにしました。

そして今、私はメモリリークがあり、それを見つけるのに助けが必要です。私はMSMFCツールを使用することから始めました

初期化の直後にいくつかの出力があります:

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を呼び出していませんが。

何が原因である可能性があるか、または原因を見つけるためにどのツールを使用できるかについてのヒント、提案、またはヒントは素晴らしいでしょう。

4

2 に答える 2

6

{ } 括弧内の番号は割り当て順序番号です。プログラムが完全に決定論的で、毎回まったく同じことを行う場合、これらの数値は実行ごとに同じままである必要があります。

その場合、このトリックを使用できます。次のコードをメイン関数の先頭に追加します。

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

次に、そのifステートメントにブレークポイントを設定して、プログラムを開始します。で停止したら、リークしたメモリの最初のブロックの割り当て順序番号と一致するよう ifに の値を変更し、プログラムを続行します。lBreakAlloc

そのメモリ ブロックを割り当てているポイントに到達したら、さあ、ちょっと!デバッガーで停止し、どの割り当てが解放されていないかを正確に確認できます。

于 2012-11-23T13:12:02.727 に答える
2

クラスのunInitメソッドKinectは間違いなくメモリ リークの原因です。すべてのフィールドは、最初にポイントされたオブジェクト (存在する場合) を削除せずに null に設定されます。また、新しいオブジェクトへのポインターを返すメソッドを少なくとも 1 つ見つけました ( 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;
}
于 2012-11-23T12:41:35.673 に答える