C# `修正了'vs GCHandle.Alloc(obj,GCHandleType.pinted)

C# `修正了'vs GCHandle.Alloc(obj,GCHandleType.pinted),c#,C#,我试图找出用fixed关键字定义的固定指针是如何工作的。我的想法是在内部使用GCHandle.Alloc(object,GCHandleType.pinted)。但当我查看为以下C代码生成的IL时: 我找不到任何GCHandle的痕迹 我看到的唯一提示是在方法中使用了固定指针,即以下IL声明: .locals init ([0] valuetype TestPointerPinning.MyObject[] arr, [1] valuetype TestPointer

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

我找不到任何
GCHandle
的痕迹

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

.locals init ([0] valuetype TestPointerPinning.MyObject[] arr,
              [1] valuetype TestPointerPinning.MyObject& pinned aptr)
因此指针被声明为pinted,并且不需要任何额外的方法调用来将其锁定

我的问题是

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

    • 好吧,当然有区别,你看到了。CLR支持多种方式固定对象。只有GCHandleType.pinted方法直接公开给用户代码。但也有其他功能,比如,在驱动程序执行重叠I/O操作时,保持I/O缓冲区固定的功能。fixed关键字使用的是,它根本不使用显式句柄或方法调用。添加这些额外的方法是为了尽可能快速、可靠地再次解开对象,这对GC健康非常重要

      固定缓冲引脚由抖动实现。当它将MSIL转换为机器代码时,它执行两个重要的任务,最明显的是机器代码本身,您可以通过调试器轻松地看到它。但它也会生成垃圾收集器使用的数据结构,在调试器中完全不可见。GC需要可靠地找到存储在堆栈帧或CPU寄存器中的对象引用。有关该数据结构的更多信息,请参阅

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


      但是不,这些技巧是不适用于C代码的,您确实需要在代码中使用fixed关键字。或GCHandle.Alloc()。如果您发现自己在pin中迷失了方向,那么您很有可能应该考虑pinvoke或C++/CLI,这样您就可以轻松地调用本机代码。pinvoke marshaller在本机代码运行时用于保持对象稳定的临时pin是不需要显式代码的自动pinning的另一个示例。

      那么,
      fixed
      是否比
      GCHandle.Alloc(xxx,GCHandleType.pinted)
      具有更好的性能?
      .locals init ([0] valuetype TestPointerPinning.MyObject[] arr,
                    [1] valuetype TestPointerPinning.MyObject& pinned aptr)