【问题标题】:Struct with reference types and GC?带有引用类型和 GC 的结构?
【发布时间】:2012-07-23 19:59:33
【问题描述】:

我想知道,

类的实例在堆上。 (其中的值类型也在堆中)。

但是相反的情况呢?

有一个问题here,但没有提及任何GC相关信息。

那么 - GC 如何处理这种情况?

public struct Point 
{
object o ;

   public int x, y;

   public Point(int p1, int p2) 
   {
   o = new Object();
      x = p1;
      y = p2;    
   }
}

【问题讨论】:

    标签: c# .net struct garbage-collection heap-memory


    【解决方案1】:

    Point 包含对堆上对象的引用。一旦该引用不再存在该 Point 的副本,它将有资格被收集。注意:

    Point p1 = new Point(1,2);
    Point p2 = p1;
    

    是 2 个副本,每个副本都有对堆上 相同 对象的引用。如果这些点存储为某个对象上的字段,那么显然该对象的生命周期将至少与具有这些字段的对象一样长。如果这些点只是堆栈上的变量,那么它会变得更加复杂,因为 GC 可能会考虑变量是否会再次读取。如果不是,则该变量可能不会有效存在(或者:它可能)。

    路径可能非常间接,但本质上归结为:GC 能否到达对象,从 GC 根开始。

    【讨论】:

    • marc 我不想想问如果这个结构本身是实例类的字段成员怎么办....:) :)
    • @RoyiNamir 简单地说,它们都将驻留在堆上;-)
    • @RoyiNamir GC 会问这个问题
    • @AdamHouldsworth 是的。那是有道理的。 (毕竟它是一种值类型)
    • @adam 是的......它是:) 只是为了开个玩笑,但它会在堆中。
    【解决方案2】:

    GC 确实在中搜索对象根

    • GC 句柄(静态变量是根,也是 GC 句柄)
    • 所有线程堆栈
    • CPU 寄存器

    在您的情况下,结构通常位于线程堆栈内,因此被搜索。如果它被装箱,则它作为伪对象驻留在托管堆上。但是你可以放心,这个东西被 GC 正确计数了。由于它确实包含一个对象,因此它不再是 blittable 类型,并且不能通过 PInvoke 传递给非托管代码。

    PInvokes 存在一个问题,如果您将结构传递给它,即使未管理的调用仍在进行中,它也会被 GC方法就剩下了。在释放模式下,GC 收集得更加积极。

    编辑1: 作为类对象中的成员的结构不是特殊情况。 GC 还将检查所有类字段以查找嵌入式结构中的类引用。

    【解决方案3】:

    结构类型的存储位置最好被认为是用 Duck® 品牌胶带固定在一起的存储位置的集合;固定在一起的存储位置的性质将是结构的性质。如果一个结构体存储在栈中,那么它的字段将被存储在栈中;如果结构存储在堆对象字段中,则其字段将存储为该堆对象的一部分;等等。如果一个结构存储在一个可变的存储位置,它的字段(公共或私有)将是可变的(即使该结构不提供突变,将一个结构复制到另一个将通过用相应的字段覆盖其字段来改变后者前者的字段)。如果一个结构体存储在一个不可变的存储位置,那么它的所有字段都是不可变的。

    如果您以这种方式看待事物,将很容易理解结构的 GC 行为本质上与通过用单独的字段替换结构所获得的 GC 行为相同(行为的唯一重要位置is 'unusual' is 'unusual' is with arrays, 因为通常一个数组槽只保存一个项目而不是一组字段;没有非结构等效于结构类型的数组)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-06-01
      • 1970-01-01
      • 2014-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多