【发布时间】:2011-10-18 12:31:43
【问题描述】:
我正在考虑使用 ref 参数来限制数组的边界检查。例如交换两个元素的代码是:
class Test {
int[] array;
private void qSort() {
...blah...
int temp = array[a];
array[a] = array[b];
array[b] = temp;
}
}
它有 4 次访问数组 替代方案是:
class Test {
int[] array;
private void qSort() {
...blah...
Swap( ref array[a], ref array[b] );
}
static void Swap(ref int a,ref int b) {
int temp = a;
a=b;
GC.Collect(); // suppose this happens
b=temp;
}
}
理论上只有 2 次访问数组
让我感到困惑的是,当我通过 ref 传递数组元素时,我不知道究竟会发生什么。如果垃圾收集器启动,在交换函数中执行代码时,将能够移动数组吗?或者数组在通话期间被固定?
请注意,上面的代码是一个简单的测试用例。我想在更复杂的场景中使用它
编辑:正如 BrokenGlass 所指出的,Eric Lippert 在这里C# parameters by reference and .net garbage collection回答了这个问题@
数组不会被固定,GCollector 可以移动它,并将相应地更新任何 ref 到它的元素,它驻留在堆栈中
【问题讨论】:
-
不要尝试过早优化,尤其是如果您对机器的工作原理没有深入了解。恰当的例子:由于拳击,您的第二个版本(使用
ref)实际上会比第一个版本慢很多(循环尝试看看)。 -
@Jon,我同意出于性能原因这样做可能没有意义,但它确实提高了可读性......顺便说一句,在这种情况下没有装箱
-
上述 SO 线程有一个 Eric Lippert 的回答,应该澄清压缩/移动问题
-
@Jon:拳击在哪里?当值类型转换为引用类型时会发生装箱,但这里没有引用类型。
-
@PanosTheof:假设我告诉过你如果下雨,那么街道就会湿。从逻辑上讲,这并不意味着正在下雨! 如果垃圾收集器移动了一块内存,那么存在某种机制,以便未完成的托管引用继续有效。在这些情况下,垃圾收集器是否真的确实移动了内存块,如果确实如此,它使用什么机制来保证托管引用的安全,我不知道。我不是垃圾收集器方面的专家。 (或者,正确地说,收集器——有很多实现。)
标签: c#