`fixed` vs GCHandle.Alloc(obj,GCHandleType.Pinned)

Max*_*Max 14 c#

我试图找出如何使用fixed关键字工作定义的固定指针.我的想法是内部GCHandle.Alloc(object, GCHandleType.Pinned)被用于此.但是当我查看为以下C#代码生成的IL时:

unsafe static void f1()
{
  var arr = new MyObject[10];
  fixed(MyObject * aptr = &arr[0])
  {
     Console.WriteLine(*aptr);
  }
}
Run Code Online (Sandbox Code Playgroud)

我找不到任何痕迹GCHandle.

我看到该方法中使用固定指针的唯一提示是以下IL声明:

.locals init ([0] valuetype TestPointerPinning.MyObject[] arr,
              [1] valuetype TestPointerPinning.MyObject& pinned aptr)
Run Code Online (Sandbox Code Playgroud)

所以指针被声明为固定,并且不需要任何额外的方法调用来固定它.

我的问题是

  • 在声明中使用固定指针和使用GCHandle类固定指针之间有什么区别吗?
  • 有没有办法在不使用fixed关键字的情况下在C#中声明固定指针?我需要这个在循环中固定一堆指针,我无法使用固定关键字来做到这一点.

Han*_*ant 18

嗯,确定有区别,你看到了.CLR支持多种方式来固定对象.只有GCHandleType.Pinned方法直接暴露给用户代码.但还有其他一些,例如"异步固定句柄",这是一种在驱动程序执行重叠I/O操作时保持I/O缓冲区固定的功能.而fixed关键字使用的那个,根本不使用显式句柄或方法调用.添加了这些额外的方法,以便尽可能快速可靠地再次取消对象,这对GC健康非常重要.

固定缓冲引脚由抖动实现.在将MSIL转换为机器代码时执行两项重要工作,高度可见的是机器代码本身,您可以使用调试器轻松查看它.但它也会生成垃圾收集器使用的数据结构,在调试器中完全不可见.GC要求可靠地查找存储在堆栈帧或CPU寄存器中的对象引用.更多关于此答案中的数据结构.

抖动使用元数据中变量声明的[pinned]属性来设置该数据结构中的位,指示变量引用的对象是临时固定的.GC看到了这一点并且知道不移动对象.非常高效,因为它不需要显式方法调用来分配句柄,也不需要任何存储.

不过没有关系,这些技巧不可,否则到C#代码,你真的需要使用固定的关键字在你的代码.或者GCHandle.Alloc().如果您发现自己迷失了引脚,那么您应该考虑使用pinvoke或C++/CLI的高概率,以便您可以轻松调用本机代码.pinvoke marshaller用来在本机代码运行时保持对象稳定的临时引脚是自动固定的另一个例子,它不需要显式代码.

  • 那么,“fixed”是否比“GCHandle.Alloc(xxx, GCHandleType.Pinned)”具有更好的性能? (4认同)