局部变量和堆栈

时间:2010-12-17 16:38:36

标签: c# clr command-line-interface

以下代码段会发生什么:

while (!Done)
{
     Data data = source.GetData();
     sink.ProcessData(data);
}

是否在每次循环迭代时将新引用data放在堆栈上(从而防止对象data引用的垃圾收集),或者是在每次迭代中重用的引用?

8 个答案:

答案 0 :(得分:8)

  

是否在每次循环迭代时将新的引用数据放在堆栈上(从而防止对象数据引用的垃圾收集),或者是在每次迭代中重用的引用?

我认为关于重复使用的“主要”问题已经得到了充分的回答,但是括号内的问题非常重要。 您认为这可以防止垃圾回收是错误的。如果垃圾收集器检测到对“数据”的唯一引用是堆栈槽并且没有人再次从它读取那么垃圾收集器甚至可以回收存储与堆栈上的引用。如果消耗堆栈槽的东西是GC不知道的非托管代码,这可能会很糟糕。

如果您需要通过在堆叠上抓住它来保持活着,那么您需要在方法中添加KeepAlive

答案 1 :(得分:2)

正如你所说,变量是“重用的”。堆栈/局部变量只是方法的本地变量,而不是范围。您的data变量所在的范围只会阻止它在该范围之外被看到,反之则不会定义不同的堆栈槽。

Jon Skeet says it well,一如既往。

答案 2 :(得分:1)

引用放在堆栈上(变量本身在堆上分配),每次迭代都会重用。相反,它在while循环结束后变得无法访问,并且有资格进行垃圾收集(除非你将它存储在接收器中的某个位置)。

答案 3 :(得分:1)

循环中的变量不会在迭代中持续存在,因此它们在每个循环中都被有效地刷新 - 编译器在它们下面做的是它的业务:)

如果它是一个引用,则指针被刷新,并且该对象对GC负责,假设您没有在其他地方挂钩。

答案 4 :(得分:1)

数据如果是引用类型总是进入堆。如果它是ValueType在这里堆叠。

引用本身将被重用。

答案 5 :(得分:1)

考虑一下:

    private class test
    {
        ~test()
        {
        }
    }

    static void Main()
    {
        while (true)
        {
            GC.Collect();
            test t = new test();
        }
    }

t在每个循环上重复使用。但是如果你在测试类的Finalizer中设置一个断点,它将在第三次重新分配变量t后被命中。

答案 6 :(得分:1)

没有任何事情发生,因为编译器会在发布生产时将其优化为类似下面的内容:

sink.ProcessData(source.GetData());

如果您创建变量并更快地取消引用它们,则会发生heap碎片,这就是我们使用循环缓冲区的原因。

答案 7 :(得分:0)

我相信每次都是一个新的例子。为什么会阻止垃圾收集?

相关问题