问题
I have a .NT class which has multiple delegates for callbacks from native code. Is it necessary to allocate all the delegates? I mean does GCHandle.Alloc()
protects just the delegate or the entire class that owns the delegate from being collected?
回答1:
A delegate has two relevant properties, Method and Target. The Target will be non-null if the delegate was created for an instance method. And that keeps the object alive, as long as the garbage collector can see the delegate instance.
Native code is relevant to having problems with callbacks. When you pass a delegate instance to a pinvoked native function then the P/Invoke marshaller will use Marshal.GetFunctionPointerForDelegate() to create a little stub that produces the required Target reference when the native code makes the callback. The garbage collector however can not see this stub and therefore won't find a reference to the delegate object. And collects it. The next callback from the native code produces a crash.
To avoid this, you must store the delegate object yourself so that it stays referenced for as long as the native code can make the callback. Storing it in a static variable is an obvious solution.
回答2:
I am wrong. You don't need to pinned the delegate (at the other hand, you cannot pinned the delegate, there will be a exception be thrown (System.ArgumentException: Object contains non-primitive or non-blittable data.)
reference: http://social.msdn.microsoft.com/Forums/vstudio/en-US/bd662199-d150-4fbf-a5ee-7a06af0493bb/interop-pinning-and-delegates?forum=
Details about that in Chris Brumme's blog http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx
Chris Brumme wrote: Along the same lines, managed Delegates can be marshaled to unmanaged code, where they are exposed as unmanaged function pointers. Calls on those pointers will perform an unmanaged to managed transition; a change in calling convention; entry into the correct AppDomain; and any necessary argument marshaling. Clearly the unmanaged function pointer must refer to a fixed address. It would be a disaster if the GC were relocating that! This leads many applications to create a pinning handle for the delegate. This is completely unnecessary. The unmanaged function pointer actually refers to a native code stub that we dynamically generate to perform the transition & marshaling. This stub exists in fixed memory outside of the GC heap.
However, the application is responsible for somehow extending the lifetime of the delegate until no more calls will occur from unmanaged code. The lifetime of the native code stub is directly related to the lifetime of the delegate. Once the delegate is collected, subsequent calls via the unmanaged function pointer will crash or otherwise corrupt the process. In our recent release, we added a Customer Debug Probe which allows you to cleanly detect this – all too common – bug in your code. If you haven’t started using Customer Debug Probes during development, please take a look!
回答3:
I think there will be something wrong happened (but not usually) when you just store the delegate object. As we all know , the managed memory will be arranged by Garbage Collect. ( That means the physical memory address of a managed object will be changed. )
Imaging there is a long-time-life delegate to be called by native code, we set the delegate as the static member or class member . But sometime (we don't know when , we just know it will happen) , GC arranged memory, and the physical memory of the delegate may from 0x000000A to 0x0000010 . But the native code know nothing about it , for the native code , it only knows to call at 0x000000A forever. So we should not only store the delegate object but also use GCHandle.Alloc to tell GC not move the physical memory of the delegate object. Then the native code will do well at callback time.
Well , because the GC do not arrange managed memory frequencly , so for a short-time-life delegate , even you do not call the GCHandle.Alloc , your codes always "DO WELL" , but sometimes it will mad. Now , you know the reason.
reference: http://dotnet.dzone.com/news/net-memory-control-use-gchandl
来源:https://stackoverflow.com/questions/4097235/is-it-necessary-to-gchandle-alloc-each-callback-in-a-class