Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

is it necessary to gchandle.alloc() each callback in a class?

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?

like image 782
ali_bahoo Avatar asked Nov 04 '10 13:11

ali_bahoo


2 Answers

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.

like image 78
Hans Passant Avatar answered Nov 15 '22 06:11

Hans Passant


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

like image 38
NorSD NorSD Avatar answered Nov 15 '22 08:11

NorSD NorSD