我似乎在某些代码中遇到内存泄漏,这些代码现在已经生产了一段时间(我看到Process / Private Bytes计数器在PerfMon中为我的进程随时间推移而上升)。请注意,除了泄漏之外,代码的工作没有问题。似乎负责的代码如下(如果我删除处理委托传递到非托管代码的代码,泄漏消失):
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并在进程开始的时候比较堆的快照,我可以看到一个上升。我最终将其追踪到:
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以直接传递委托,让marshaller为我处理它,但是仍然会发生泄漏。
更新:我更新了Dispose()代码,我原来的帖子有一些拼写错误。
答案 0 :(得分:2)
只需使用委托参数而不是IntPtr
声明您的原生方法。编组人员会为你做所有这些事情。
答案 1 :(得分:0)
据我所知委托是C#中的函数指针列表。将它传递给C ++中的函数指针参数让我觉得会有问题。您应该考虑添加一个本机函数来报告状态,并将此函数汇集到C#中的单独线程或后台工作程序中。这样你就不需要再传递委托了。