C# 无限循环中创建的对象的垃圾回收

C# 无限循环中创建的对象的垃圾回收,c#,garbage-collection,C#,Garbage Collection,我有一个非常基本的问题 我写了这样一个循环: while(true) { MyTestClass myObject = new MyTestClass(); } 何时在中创建对象 循环,垃圾收集 而且,对于每一次迭代,都是这样吗 新的内存位置是 是否已分配给myObject引用 如果我写myObject=null在每次迭代结束时 坦白地说,只要GC愿意;变量永远不会被读取,因此它总是合格的 myObject是一个变量,它在堆栈上有一个固定的位置作为参考;但是,每个新MyTestClass

我有一个非常基本的问题

我写了这样一个循环:

while(true)
{
   MyTestClass myObject = new MyTestClass();
}
  • 何时在中创建对象 循环,垃圾收集
  • 而且,对于每一次迭代,都是这样吗 新的内存位置是 是否已分配给myObject引用
  • 如果我写
    myObject=null在每次迭代结束时
  • 坦白地说,只要GC愿意;变量永远不会被读取,因此它总是合格的
  • myObject
    是一个变量,它在堆栈上有一个固定的位置作为参考;但是,每个
    新MyTestClass()
    都是一个不同的对象,在可用堆空间的某个地方创建;每次都不一样
  • 没有任何区别;严格地说,变量的实际声明点(在IL中)以及如何实际实现
    (而
    )存在一些复杂性,但这只有在退出循环后才会显示出来。因为在每次迭代中您都会立即分配它,所以这里没有明显的区别
  • 什么时候在循环中创建对象,回收垃圾

    在删除最后一次引用后的某个时间点。每次循环迭代都会创建并删除一个新引用,因此GC可以在需要时自由地收集这些对象。实际上,当您的程序完全填满第0代时,很可能会发生这种情况

    此外,对于每次迭代,是否将新的内存位置分配给myObject引用

    如果我写
    myObject=null在每次迭代结束时


    这没什么区别。设置
    myObject=null
    删除对对象的引用,但在下一次循环迭代中重新分配
    myObject
    变量时,引用仍然会被删除。

    让我们来澄清一些事情。每次点击循环的内部,
    myObject
    将被分配到一个新地址。所以这个循环所做的就是为一个变量名分配新的内存地址。因此:

  • GC将垃圾收集所有以前的分配,可能几乎是立即进行的,因为从未使用过该变量
  • 没关系。该变量仍然未使用

  • 作为所有其他答案的补充:


    你可以把你的类变成一个结构。然后它将在堆栈上,并在每次迭代中被丢弃。如果您的结构生成了新类,那么您就回到了原点。如果结构较大,则可能会对性能产生负面影响;如果结构较小,则可能会对性能产生正面影响

    让我们添加一些实际使用对象的代码,以便更清楚地了解实际发生的情况:

    while(true) {
      // Here a new instance is created in each iteration:
      MyTestClass myObject = new MyTestClass();
      // Here the instance is still in use
      // until here:
      myObject.CallSomething();
      // Here the instance isn't used any more,
      // so the GC can collect it if it wants to.
      // Setting the reference to null here:
      myObject = null;
      // is useless, as the GC already knows that the
      // instance is unused before that time.
    }
    

    这是你的最后一点;在IL级别(这是GC关心的),作用域不存在,并且在IL前导中声明了
    myObject
    (假设它没有被捕获),因此在方法的整个持续时间内都存在(作为带有值的“局部”)。离开(C#)范围时,它不会被明确清除。简单地说:它永远不会超过这一点。您确定变量在每次传递时都必须有一个固定的位置吗?既然变量声明在循环中,那么这不是一个更动态的场景吗?如果您在循环中使用myObject的不同“实例”构造一个Lambda表达式,并且该表达式的生命周期超出了循环,那么您就能够捕获它们了?或者这是一个编译器技巧?myObject变量在堆栈上的位置固定是否正确?我认为,每次在堆栈上创建名为“myObject”的新变量时(在上一次迭代中创建的变量显然会被删除)。我说的对吗?@Tormod在这种情况下,将动态创建lambda闭包中字段的存储,并通过复制变量中的值填充字段,但这不会影响变量在堆栈上的位置。@Tormod-如@Pete所示;如果你捕获它,它就不再是“本地”;本地堆栈将具有对引用变量(现在是字段)的对象的引用。每个循环是否获得不同的捕获对象取决于变量的确切定义位置;在这种情况下,每个循环将获得一个新的捕获对象。而且每次捕获实例也会被收集(当GC感觉像的时候)。+1如果你认为null是空的,那么一旦GC不再使用,运行时会使这些实例对GC来说是可省略的,这意味着即使在声明大量对象变量的大方法中,在方法中部分地将它们置零(虽然可读),不会导致行为上的差异。@Adam:如果是这样,那么我们应该在什么时候为对象指定null值?当我们知道变量在某些代码行之后(例如myObject.CallSomething()之后)不会使用时,不将其设置为null可以吗?@Amey是的,对不起,我不是很清楚-不需要将其设置为null,运行时有智能为您解决此问题。这是不正确的。如果它是一个结构,那么每次迭代都不会丢弃它,每次迭代都会是同一个实例,并且在方法退出之前不会丢弃它。但是,每次迭代都会得到一个新的值。这是否意味着,在struct的情况下,将使用相同的变量,但在每次迭代中它的属性将有不同的值?i、 e.在循环中声明的struct变量不会在每次迭代结束时从堆栈中移除。我说的对吗?循环变量是否被弹出取决于编译器,但这些变量的行为是在每次迭代中被重置(全新的)。如果你想让一个变量值在iTraion上继续存在,你需要在循环之外声明它。我说的“丢弃”只是意味着你不能访问以前的数据。它是清除堆栈上的数据,还是弹出堆栈,然后推送堆栈,对于GC来说并不重要。第一个是有点