1

しばらくの間運用されていた一部のコードでメモリ リークが発生しているようです (プロセスの PerfMon で時間の経過とともに Process\Private Bytes カウンターが上昇していることがわかります)。コードはリーク以外の問題なく動作することに注意してください。責任があると思われるコードは次のとおりです (アンマネージ コードにデリゲートを渡すコードを削除すると、リークはなくなります)。

private MyDelegate _myDelegate = null;
private GCHandle _myHandle;

public MyClass()
{
    _myDelegate = new MyDelegate(target);
    _myHandle = GCHandle.Alloc(_myDelegate);

    if (NativeCalls.UnmanagedFunctionCall(_myDelegate))
    {
        ...
    }
}

public void Dispose()
{
    GC.SuppressFinalize(this);
    Dispose(true);
}

~MyClass()
{
    Dispose(false);
}

protected void Dispose(bool disposing)
{
    ...
    if (_myHandle.IsAllocated)
    {
        _myHandle.Free();
    }
    ...
}

....

テスト コードは、ループ内で MyClass のインスタンスを作成して破棄するだけです。

したがって、基本的には、クラス コンストラクターでアンマネージ コードに渡すデリゲートがあり、GCHandle でラップして収集が早すぎないようにし、アンマネージ コードがそれを使用しようとしたときに何らかのアクセス違反が発生するのを防ぎます。WinDbg を使用し、プロセスがかなり後で開始されたときにヒープのスナップショットを比較すると、1 つが上昇していることがわかります。私は最終的にそれを追跡します:

0:005> !heap -p -a 0bd779c8
address 0bd779c8 found in
_HEAP @ 400000
  HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
    0bd779a0 000c 0000  [00]   0bd779c8    00024 - (busy)
    Trace: 09c3
    59aba6a7 verifier!AVrfpDphNormalHeapAllocate+0x000000d7
    59ab8f6e verifier!AVrfDebugPageHeapAllocate+0x0000030e
    77260d06 ntdll!RtlDebugAllocateHeap+0x00000030
    7721ae7e ntdll!RtlpAllocateHeap+0x000000c4
    771c3cee ntdll!RtlAllocateHeap+0x0000023a
    59accb62 verifier!AVrfpRtlAllocateHeap+0x00000092
    7004691a clr!EEHeapAlloc+0x000000cb
    70047f46 clr!CExecutionEngine::ClrHeapAlloc+0x0000004a
    70047f15 clr!ClrHeapAlloc+0x00000023
    7004fd84 clr!operator new+0x00000038
    701392d1 clr!UMEntryThunk::CreateUMEntryThunk+0x0000000f
    70139473 clr!MarshalNative::GetFunctionPointerForDelegateInternal+0x000000d6
    6acd8448 mscorlib_ni+0x00238448

GetFunctionPointerForDelegateInternal() が呼び出されたときに割り当てが発生しているように見えますが、解放されていないため、マネージド デリゲート オブジェクトがガベージ コレクションを取得していない可能性があるため、リークが発生していますか? しかし、GCHandle を解放しているので、ここで何が欠けているのでしょうか?

注:管理されていない呼び出しを空にしようとしたので、基本的には何もしません。それでもリークが発生するため、管理されている側で何か問題があることがわかります。

更新: Marshal.GetFunctionPointerForDelegate() への呼び出しを削除し、デリゲートを直接渡すように p/invoke を変更して、マーシャラーに処理させることを提案しましたが、それでもリークが発生します。

更新: Dispose() コードを更新しました。元の投稿にタイプミスがありました。

4

2 に答える 2

2

の代わりにデリゲート パラメータを使用してネイティブ メソッドを宣言するだけですIntPtr。マーシャラーは、このすべての作業を行います。

于 2012-09-13T16:54:17.717 に答える
0

私の知る限り、デリゲートは C# の関数ポインターのリストです。それをC++の関数ポインタのパラメータに渡すと、問題があると感じます。ステータスを報告し、これを C# の別のスレッドまたはバックグラウンド ワーカーにプールするネイティブ関数を追加することを検討する必要があります。デリゲートを渡す必要がないようにします。

于 2012-09-13T17:57:40.520 に答える