究竟是什么'固定'做什么?

时间:2013-04-15 18:57:12

标签: c# .net

在不安全的环境中,我有一些看起来像这样的代码:

 ValidatePartialOperation(array, startingOffset, runLength);

 fixed (double* _op = array)
 {
     double* op = _op + startingOffset;
     callSomething(op, runLength);
 }

我有这个副本+粘贴在几个不同的地方。但我讨厌在多个地方进行这种验证和指针算法,所以我想将逻辑组合在一起,看起来像是一行:

 double* op = preCall(array, startingOffset, runLength);
 callSomething(op, runLength);
 postCall(array);

甚至更好:

 using (double* op = preCall(array, startingOffset, runLength))
 {
     callSomething(op, runLength);
 }

但无论发生什么,我都不能失去“固定”版本的性能。

我现在的计划是模仿固定语句正在做什么,但我实际上并不知道那是什么。可能是一些带有钉扎操作的try-catch块?

5 个答案:

答案 0 :(得分:5)

当然,你可以做到。是否能满足您的性能需求,我不知道;你应该测量并找出答案。

要修复数组并获取指针而不使用fixed语句,可以使用GCHandle对象。使用“固定”句柄类型调用GCHandle.Alloc,传入数组,然后您将返回IntPtr,您可以安全地转换为指针。在Free调用GCHandle之前,该数组将保持固定状态,因此确保您不会忘记GCHandle 。只要该句柄非常出色,您就会破坏垃圾收集器的性能。

但我的建议是使用fixed语句。这就是它的用途。

答案 1 :(得分:4)

仅仅为了未来的读者,我想我已经很好地弄明白了,尽管经过一些有根据的猜测。

基本上,fixed似乎是调用C ++ / CLI pin_ptr的C#方式。这些是必须在堆栈上声明为局部变量的特殊变量。它们似乎没有直接与GC通信,因此它们的重量非常轻。相反,当GC运行时,它足够聪明,可以搜索所有活动线程的调用堆栈,并检查是否有任何函数的变量是这些特殊的固定指针。如果它们是,它们指向的任何东西都标记为固定,并且在垃圾收集期间不会在内存中移动。

相比之下,GCHandle.Alloc(obj, GCHandleType.Pinned)实际上与GC通信并将对象放在不移动的对象列表中。这意味着,每当您GCHandle.Alloc然后Free时,您就会在列表中添加和删除元素并开展工作。固定指针是一种完全被动的机制,不需要做任何额外的工作。这也解释了为什么你不能改变固定指针的值:只要固定指针指向它,它指向的管理对象只能保证固定。如果固定指针指向不同的对象,则 it 现在将被固定。如果你将固定指针设置为null,即使只是片刻,它也不再固定任何东西,你到目前为止所做的所有指针数学都会失效。

这解释了当我尝试切换到GCHandles时的性能影响。所以fixed不仅仅是最好的工具,它只是 工具,至少在性能很重要时。即使语法有时很尴尬。

答案 2 :(得分:0)

fixed修复了在内存压缩过程中阻止垃圾收集器重定位对象的问题。如果您不使用它,那么您的对象可以随时移动,指针将变为无效。

答案 3 :(得分:0)

不,不是那样的。就像MSDN说:Fixed语句阻止垃圾收集器移动内存,这样只要需要,你的固定指针就会保持有效。如果您正在使用某些非托管资源,这一点很重要。就我目前所知,您不能将其替换为任何usingtry/catch/finally或其他任何内容。

答案 4 :(得分:0)

fixed固定变量,防止垃圾收集器在fixed块的持续时间内移动对象。

根据the documentation

  

C#编译器只允许您在固定语句中为托管变量分配指针。

因此,似乎您可能无法在代码中使用fixed语句。