If the pointer is received on a regular array - it is clear, it is necessary to fix, even in the examples there is such a thing on msdn. And if the pointer is received from IntPtr or is IntPtr itself - is it necessary to fix? How to understand when to fix, and when not to?


Allocate unmanaged memory:

internal unsafe class Memory { // Heap API flags private const uint HEAP_ZERO_MEMORY = 0x00000008; // Heap API functions [DllImport("Kernel32")] private static extern IntPtr GetProcessHeap(); [DllImport("Kernel32")] private static extern int HeapSize(IntPtr hHeap, uint dwFlags, IntPtr lpMem); [DllImport("Kernel32")] private static extern IntPtr HeapAlloc(IntPtr hHeap, uint dwFlags, UIntPtr dwBytes); [DllImport("Kernel32")] private static extern IntPtr HeapReAlloc(IntPtr hHeap, uint dwFlags, IntPtr lpMem, UIntPtr dwBytes); [DllImport("Kernel32")] private static extern bool HeapFree(IntPtr hHeap, uint flags, IntPtr lpMem); // Handle for the process heap. This handle is used in all calls to the // HeapXXX APIs in the methods below. private static IntPtr ph = GetProcessHeap(); // Private instance constructor to prevent instantiation. private Memory() { } // Allocates a memory block of the given size. The allocated memory is // automatically initialized to zero. public static IntPtr Alloc(int size) { IntPtr result = HeapAlloc(ph, HEAP_ZERO_MEMORY, new UIntPtr((uint)size)); if (result == null) throw new OutOfMemoryException(); return result; } // Frees a memory block. public static void Free(IntPtr block) { if (!HeapFree(ph, 0, block)) throw new InvalidOperationException(); } // Re-allocates a memory block. If the reallocation request is for a // larger size, the additional region of memory is automatically // initialized to zero. public static IntPtr ReAlloc(IntPtr block, int size) { IntPtr result = HeapReAlloc(ph, HEAP_ZERO_MEMORY, block, new UIntPtr((uint)size)); if (result == null) throw new OutOfMemoryException(); return result; } // Returns the size of a memory block. public static int SizeOf(IntPtr block) { int result = HeapSize(ph, 0, block); if (result == -1) throw new InvalidOperationException(); return result; } } 

We declare IntPtr as a class field:

  class Program { static IntPtr buffer = IntPtr.Zero; static unsafe void Main(string[] args) { buffer = Memory.Alloc(100); byte* ptr = (byte*)buffer.ToPointer(); // Не снесет ли сборщик мусора указатель ptr в произвольном месте? Console.Read(); } } 

    1 answer 1

    You need to fix managed objects when passing to native code or when using pointers inside unsafe code, so that when garbage collection occurs, the pointer is not defragmented. Typically, IntPtr in managed code is a pointer to memory from the native, which, unlike .Net, is not subject to garbage collection and defragmentation.

    Only managed objects are committed. IntPtr is not one of those, since the structure

    That is, if you received an IntPtr, you can get data using Marshal methods

     var str= Marshal.PtrToStringUni(Marshal.ReadIntPtr(Элемент)); 

    You can also send a link or copy data for example.

     var ИсточникPrt = Marshal.StringToHGlobalUni(Источник); var СообщениеPrt = Marshal.StringToHGlobalUni(Сообщение); var ДанныеPrt = Marshal.StringToHGlobalUni(Данные); ВнешнееСобытие1С(ИсточникPrt, СообщениеPrt, ДанныеPrt); Marshal.FreeHGlobal(ИсточникPrt); Marshal.FreeHGlobal(СообщениеPrt); Marshal.FreeHGlobal(ДанныеPrt); 

    Where External Event 1C is a delegate to a native function obtained through

     // Делегат для выделения памяти на стороне неуправляемого кода internal static ВыделитьПамятьDelegate ВыделитьПямять; //Делегат для сообщения об ошибке в неуправляемый код internal static ИнформацияОбОшибкеDelegate ИнформацияОбОшибке; internal static ВнешнееСобытие1СDelegate ВнешнееСобытие1С; internal static string CoreClrDir, NetObjectToNativeDir; //Вызвается из натива. Устанавливаем нужные делегаты public static void SetDelegate(IntPtr ДляВыделенияПамяти, IntPtr ДляВызоваОшибки, IntPtr ДляВызоваВнешнегоСобытия) { ВыделитьПямять = Marshal.GetDelegateForFunctionPointer<ВыделитьПамятьDelegate>(ДляВыделенияПамяти); ИнформацияОбОшибке = Marshal.GetDelegateForFunctionPointer<ИнформацияОбОшибкеDelegate>(ДляВызоваОшибки); ВнешнееСобытие1С = Marshal.GetDelegateForFunctionPointer<ВнешнееСобытие1СDelegate>(ДляВызоваВнешнегоСобытия); } 

    Well, see GCHandle.Alloc GCHandle.Free

    https://msdn.microsoft.com/ru-ru/library/system.runtime.interopservices.gchandle.free(v=vs.110).aspx

    • Ie, you need to fix only managed objects, the same arrays of bytes - if we take a pointer from them? The same allocated unmanaged memory wrapped in intPtr - will not be affected by the collector, even if we receive a pointer from IntPtr? - Align
    • Lord, how vyrviglazno looks Cyrillic in the names of variables. 5 minutes, complement the question with an example. - Align
    • one
      Yes. See examples. In the native link is fixed in the heap. There is no defragmentation. - Serginio
    • This is from the habit. I am so very comfortable. I'm 1C nickname - Serginio
    • Added sample code to the question. Judging by your answer, nothing terrible with ptr in the Main method should happen. - Align