使用P / Invoke编组IntRef

时间:2014-10-28 13:25:29

标签: .net pinvoke

当我使用IntPtr保留内存并将动态数组传递给本机代码时,在C#/托管端初始化此内存并将其传递给我的本机DLL之后,这块内存是固定还是复制的?即如果我在我的本机代码中修改数组,我会在托管代码中看到修改吗?

我知道没有必要使用IntPtr,但由于数组嵌入到复杂的结构中,所以看起来更方便。

1 个答案:

答案 0 :(得分:2)

在.NET程序中获取内存分配的IntPtr的唯一有效方法是:

  • 使用Marshal.AllocXxx()方法之一。这不是固定内存,它是不可移动的内存,从其中一个操作系统堆分配。操作系统通常不支持更改分配地址的概念,一旦它被分配,它将永远停留在同一地址。只有垃圾收集器具有必要的魔力,他们可以找到指向内存块的指针并知道如何更新它们。
  • 使用GCHandle.AddrOfPinnedObject()。从GC堆分配,地址将保持稳定,直到调用GCHandle.Free()。只有在分配需要存在很短时间的情况下才能使用它。
  • 使用C#修复关键字。这是GCHandle的高度优化版本,无需分配句柄即可运行。通过将变量标记为特殊的抖动来实现,当GC走到堆栈,寻找根时,它将被GC发现。否则它具有与GCHandle完全相同的效果,GC认为固定语句的目标固定并且不会移动对象。

对后两个项目符号非常小心,特别是 fixed 关键字需要不安全,因为它很危险。一旦代码执行离开固定语句的范围,停止使用IntPtr非常重要。当运行时没有强制执行时,当GC发现堆已损坏时,失败模式是完全不可识别的ExecutionEngineException。由于代码在移动后通过IntPtr写入内存块,从而覆盖了其他内容。