1
votes

When I use IntPtr to reserve memory and pass a dynamic array to native code, after I initialize this memory on the C#/managed side and pass it to my native DLL, is this chunk of memory pinned or copied? I.e. if I modify the array within my native code, will I see the modifications back in my managed code?

I know it is not necessary to use IntPtr, but since the array is embedded into a complex struct, it seems more convenient.

1
Are you talking about Marshal.AllocHGlobal? It allocates native non-movable memory block and returns IntPtr pointing to it. If you pass this IntPtr to native function, and it changes the memory, C# can see these changes. The memory is not released automatically, use Marshal.FreeHGlobal for this.Alex F
Yes, I think this answers my question. So memory allocated with Marshal.AllocHGlobal is ALWAYS pinned.sapito
Yes, this is native memory, GC doesn't work with it.Alex F
Well, it depends on how you allocate the memory. You did not say.David Heffernan

1 Answers

2
votes

The only valid ways to obtain an IntPtr for a memory allocation in a .NET program are:

  • by using one of the Marshal.AllocXxx() methods. This is not pinned memory, it is unmovable memory, allocated from one of the operating system heaps. Operating systems in general do not support the notion of changing the address of an allocation, once it is made it is stuck at the same address forever. Only garbage collectors have the necessary magic, they can find pointers to the memory block back and know how to update them.
  • by using GCHandle.AddrOfPinnedObject(). Allocated from the GC heap, the address will be stable until GCHandle.Free() is called. Only use it if the allocation needs to exist for short amounts of time.
  • by using the C# fixed keyword. This is a highly optimized version of GCHandle which works without having to allocate a handle. Achieved by the jitter marking the variable as special, it will be discovered by the GC when it walks the stack, looking for roots. It otherwise has the exact same effect as GCHandle, the GC considers the target of the fixed statement pinned and won't move the object.

Be very careful with the latter two bullets, especially with the fixed keyword which requires unsafe since it is dangerous. Very important to stop using the IntPtr once code execution leaves the scope of the fixed statement. Not enforced by the runtime, the failure mode is a completely undiagnosable ExecutionEngineException when the GC discovers that the heap got corrupted. Caused by code writing through the IntPtr into the memory block after it got moved, thus overwriting something else.