Does gchandle.alloc () need every callback in the class?

I have a .NT class that has several delegates for callbacks from native code. Should all delegates be highlighted? I mean, GCHandle.Alloc() protect only the delegate or the whole class that owns the delegate collection?

+4
source share
3 answers

A delegate has two relevant properties: a method and a goal. The target will be nonempty if a delegate was created for the instance method. And this keeps the object alive until the garbage collector can see the delegate instance.

Native code is related to callback issues. When you pass a delegate instance to a pinvoked native function, the P / Invoke marshaller will use Marshal.GetFunctionPointerForDelegate () to create a small stub that creates the desired Target link when the inner code calls back. However, the garbage collector does not see this stub and therefore will not find a reference to the delegate object. And collects it. The next callback from native code causes a failure.

To avoid this, you must save the delegate object yourself so that it remains a reference while the native code can call back. Storing it in a static variable is an obvious solution.

+7
source

I think something wrong will happen (but not usually) when you just save the delegate object. As we all know, managed memory will be organized by the Garbage Collect. (This means that the physical memory address of the managed entity will be changed.)

Imaging there is a delegate with a long service life, which is called using its own code, we set the delegate as a static member or a member of the class. But sometimes (we don’t know when, we just know that this will happen), the GC organized the memory, and the physical memory of the delegate can be from 0x000000A to 0x0000010. But the native code does not know anything about this, for its own code, it only knows to call 0x000000A forever. Therefore, we must not only store the delegate object, but also use GCHandle.Alloc to tell the GC not to move the physical memory of the delegate object. Then the native code will work well during the callback.

Good, because the GC does not arrange managed memory often, so for a delegate with a short lifetime, even you do not call GCHandle.Alloc, your codes are always "DO WELL", but sometimes it will be crazy. Now you know the reason.

link: http://dotnet.dzone.com/news/net-memory-control-use-gchandl

+1
source

I am wrong. You do not need to attach a delegate (on the other hand, you cannot attach a delegate, there will be an exception exception (System.ArgumentException: Object contains non-primitive or irreproducible data.)

link: http://social.msdn.microsoft.com/Forums/vstudio/en-US/bd662199-d150-4fbf-a5ee-7a06af0493bb/interop-pinning-and-delegates?forum=

Details on this at Chris Brumme's blog http://blogs.msdn.com/cbrumme/archive/2003/05/06/51385.aspx

Chris Brumme wrote: At the same time, managed delegates can be bound to unmanaged code, where they appear as unmanaged function pointers. Calls to these pointers will perform an unmanaged managed transition; amendment of the convocation agreement; Logging into the correct AppDomain and any necessary argument marshaling. Obviously, an unmanaged function pointer must reference a fixed address. It would be a disaster if the GC moved it! This leads to the fact that many applications create pinning for the delegate. This is completely unnecessary. An unmanaged function pointer actually refers to native code that we dynamically generate to perform the transition and marshaling. This stub exists in fixed memory outside the GC heap.

However, the application is responsible for extending the delegate for a while until more calls from unmanaged code are called. The lifetime of a native code stub is directly related to the lifetime of a delegate. After the delegate is assembled, subsequent calls using the unmanaged function pointer will cause crashes or otherwise damage the process. In our recent release, we added a client debugging probe that allows you to clearly identify this - too common - error in your code. If you did not start using trial client debugging during development, please take a look!

+1
source

All Articles