我试图了解如何使用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);
}
}
我无法找到GCHandle
的任何痕迹。
我看到该方法中使用固定指针的唯一提示是以下IL声明:
.locals init ([0] valuetype TestPointerPinning.MyObject[] arr,
[1] valuetype TestPointerPinning.MyObject& pinned aptr)
因此,指针被声明为固定,并且不需要任何其他方法调用来固定它。
我的问题是
GCHandle
类固定指针之间有什么区别吗?fixed
关键字的情况下在C#中声明固定指针?我需要这个在循环中固定一堆指针,我无法用固定关键字做到这一点。答案 0 :(得分:17)
嗯,确定有区别,你看到了。 CLR支持多种方式来固定对象。只有GCHandleType.Pinned方法直接暴露给用户代码。但还有其他一些功能,如"async pinned handles",这是一种在驱动程序执行重叠I / O操作时保持I / O缓冲区固定的功能。而 fixed 关键字使用的那个,根本不使用显式句柄或方法调用。添加了这些额外的方法,使对象尽可能快速可靠地取消固定,对GC健康非常重要。
固定缓冲引脚由抖动实现。在将MSIL转换为机器代码时执行两个重要作业,高度可见的是机器代码本身,您可以使用调试器轻松查看它。但它也会生成垃圾收集器使用的数据结构,在调试器中完全不可见。 GC要求可靠地查找存储在堆栈帧或CPU寄存器中的对象引用。有关this answer中的数据结构的更多信息。
抖动使用元数据中变量声明的[pinned]属性在该数据结构中设置一个位,表示该变量引用的对象是临时固定的。 GC看到了这一点并且知道不移动对象。非常高效,因为它不需要显式方法调用来分配句柄,也不需要任何存储。
但不是,这些技巧不适用于C#代码,你真的做需要在你的代码中使用 fixed 关键字。或者GCHandle.Alloc()。如果您发现自己迷失了引脚,那么您应该考虑使用pinvoke或C ++ / CLI的高概率,以便您可以轻松调用本机代码。 pinvoke marshaller用来在本机代码运行时保持对象稳定的临时引脚是自动固定的另一个例子,不需要显式代码。